From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:11:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:11:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433277.686236 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfnz-0008Si-8j; Tue, 01 Nov 2022 01:11:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433277.686236; Tue, 01 Nov 2022 01:11:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfnz-0008Sb-5t; Tue, 01 Nov 2022 01:11:03 +0000
Received: by outflank-mailman (input) for mailman id 433277;
 Tue, 01 Nov 2022 01:11:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfnx-0008SV-V6
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:01 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfnx-0004gr-UG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfnx-0007ff-TA
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=uIVKwSNTKxCXtacnN5WGCYbsIzuF9cQr/kbEVhbOssA=; b=D9UPni3udPydzpx/X+yshFF4pe
	JEqnC7PNUuq1IGeaq7qZ3s+NelXOLgdplJW8FFasJCwA42H6LLB//sLSKK3WHNFNrkkEEki/UQlxj
	2yns9x9EUBM92msjvXg5ILauwZDc4PZ6Ie+pdF0mejPWVbZioP67uwq+m0Nyrk33Ks4U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] VMX: correct error handling in vmx_create_vmcs()
Message-Id: <E1opfnx-0007ff-TA@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:11:01 +0000

commit 3885fa42349c3c6f31f0e0eec3b4605dca7fdda9
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Mon Oct 31 13:31:26 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:31:26 2022 +0100

    VMX: correct error handling in vmx_create_vmcs()
    
    With the addition of vmx_add_msr() calls to construct_vmcs() there are
    now cases where simply freeing the VMCS isn't enough: The MSR bitmap
    page as well as one of the MSR area ones (if it's the 2nd vmx_add_msr()
    which fails) may also need freeing. Switch to using vmx_destroy_vmcs()
    instead.
    
    Fixes: 3bd36952dab6 ("x86/spec-ctrl: Introduce an option to control L1D_FLUSH for HVM HAP guests")
    Fixes: 53a570b28569 ("x86/spec-ctrl: Support IBPB-on-entry")
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Reviewed-by: Kevin Tian <kevin.tian@intel.com>
    master commit: 448d28309f1a966bdc850aff1a637e0b79a03e43
    master date: 2022-10-12 17:57:56 +0200
---
 xen/arch/x86/hvm/vmx/vmcs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index dd817cee4e..237b13459d 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -1831,7 +1831,7 @@ int vmx_create_vmcs(struct vcpu *v)
 
     if ( (rc = construct_vmcs(v)) != 0 )
     {
-        vmx_free_vmcs(vmx->vmcs_pa);
+        vmx_destroy_vmcs(v);
         return rc;
     }
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:11:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:11:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433278.686240 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfo9-0008W3-AI; Tue, 01 Nov 2022 01:11:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433278.686240; Tue, 01 Nov 2022 01:11:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfo9-0008Vv-7i; Tue, 01 Nov 2022 01:11:13 +0000
Received: by outflank-mailman (input) for mailman id 433278;
 Tue, 01 Nov 2022 01:11:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfo8-0008Vh-1o
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfo8-0004h2-17
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfo8-0007g8-09
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=6pHIJpY0MiUktaKLMuL6rDAQxrtlFbNjfAT+HRp0jUk=; b=YQp/HJFaODQ6AXYABhYdeYyz4Q
	f8PWfIbEH2ctkjhB2b0cAy91Lq8J2kDr7HA+QW7MDKGPiiPXyCcEnpa303zVkPve4F8ADsUsH7jXH
	3gABijMCdVfQKuOFezBMLFuLWcTA6dyTABZfwcutlyEXXwpDMb4UjSzo19N8xQAttHqY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] argo: Remove reachable ASSERT_UNREACHABLE
Message-Id: <E1opfo8-0007g8-09@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:11:12 +0000

commit 916668baf9252ac30260e3394278a098712c5d34
Author:     Jason Andryuk <jandryuk@gmail.com>
AuthorDate: Mon Oct 31 13:32:59 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:32:59 2022 +0100

    argo: Remove reachable ASSERT_UNREACHABLE
    
    I observed this ASSERT_UNREACHABLE in partner_rings_remove consistently
    trip.  It was in OpenXT with the viptables patch applied.
    
    dom10 shuts down.
    dom7 is REJECTED sending to dom10.
    dom7 shuts down and this ASSERT trips for dom10.
    
    The argo_send_info has a domid, but there is no refcount taken on
    the domain.  Therefore it's not appropriate to ASSERT that the domain
    can be looked up via domid.  Replace with a debug message.
    
    Signed-off-by: Jason Andryuk <jandryuk@gmail.com>
    Reviewed-by: Christopher Clark <christopher.w.clark@gmail.com>
    master commit: 197f612b77c5afe04e60df2100a855370d720ad7
    master date: 2022-10-14 14:45:41 +0100
---
 xen/common/argo.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xen/common/argo.c b/xen/common/argo.c
index 49be715f63..2b0d980d4b 100644
--- a/xen/common/argo.c
+++ b/xen/common/argo.c
@@ -1299,7 +1299,8 @@ partner_rings_remove(struct domain *src_d)
                     ASSERT_UNREACHABLE();
             }
             else
-                ASSERT_UNREACHABLE();
+                argo_dprintk("%pd has entry for stale partner d%u\n",
+                             src_d, send_info->id.domain_id);
 
             if ( dst_d )
                 rcu_unlock_domain(dst_d);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:11:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:11:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433279.686244 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfoJ-00007j-Bz; Tue, 01 Nov 2022 01:11:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433279.686244; Tue, 01 Nov 2022 01:11:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfoJ-00007a-9C; Tue, 01 Nov 2022 01:11:23 +0000
Received: by outflank-mailman (input) for mailman id 433279;
 Tue, 01 Nov 2022 01:11:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoI-00007G-5g
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoI-0004hM-4w
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoI-0007gX-3Q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=4d1FGGcwDw0POcttXvnp7rjbGjcFvYJiJ25pe3ZJLlY=; b=pP2ZsOXTjNl6fGfFfFRYTXg1pQ
	xFTC7VnZBF3HhkXrEzpntUtvyC9Mh5T12TIXuwYg7jwuocU0ZZgoizjTe66Hj/o/BB0ixKXyq2zOo
	4OeKgDAYMMa3LNwJ7d7YK6wc+ZvKPd7EqHwr6Q4X6ogUubVCcwsTlq3eJtbj9RcCO7AY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] EFI: don't convert memory marked for runtime use to ordinary RAM
Message-Id: <E1opfoI-0007gX-3Q@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:11:22 +0000

commit b833014293f3fa5a7c48756ce0c8c9f3e4a666ff
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Mon Oct 31 13:33:29 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:33:29 2022 +0100

    EFI: don't convert memory marked for runtime use to ordinary RAM
    
    efi_init_memory() in both relevant places is treating EFI_MEMORY_RUNTIME
    higher priority than the type of the range. To avoid accessing memory at
    runtime which was re-used for other purposes, make
    efi_arch_process_memory_map() follow suit. While in theory the same would
    apply to EfiACPIReclaimMemory, we don't actually "reclaim" or clobber
    that memory (converted to E820_ACPI on x86) there (and it would be a bug
    if the Dom0 kernel tried to reclaim the range, bypassing Xen's memory
    management, plus it would be at least bogus if it clobbered that space),
    hence that type's handling can be left alone.
    
    Fixes: bf6501a62e80 ("x86-64: EFI boot code")
    Fixes: facac0af87ef ("x86-64: EFI runtime code")
    Fixes: 6d70ea10d49f ("Add ARM EFI boot support")
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    master commit: f324300c8347b6aa6f9c0b18e0a90bbf44011a9a
    master date: 2022-10-21 12:30:24 +0200
---
 xen/arch/arm/efi/efi-boot.h | 3 ++-
 xen/arch/x86/efi/efi-boot.h | 4 +++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h
index cf9c37153f..37d7ebd59a 100644
--- a/xen/arch/arm/efi/efi-boot.h
+++ b/xen/arch/arm/efi/efi-boot.h
@@ -149,7 +149,8 @@ static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *
 
     for ( Index = 0; Index < (mmap_size / desc_size); Index++ )
     {
-        if ( desc_ptr->Attribute & EFI_MEMORY_WB &&
+        if ( !(desc_ptr->Attribute & EFI_MEMORY_RUNTIME) &&
+             (desc_ptr->Attribute & EFI_MEMORY_WB) &&
              (desc_ptr->Type == EfiConventionalMemory ||
               desc_ptr->Type == EfiLoaderCode ||
               desc_ptr->Type == EfiLoaderData ||
diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h
index 84fd779314..3c3b3ab936 100644
--- a/xen/arch/x86/efi/efi-boot.h
+++ b/xen/arch/x86/efi/efi-boot.h
@@ -183,7 +183,9 @@ static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable,
             /* fall through */
         case EfiLoaderCode:
         case EfiLoaderData:
-            if ( desc->Attribute & EFI_MEMORY_WB )
+            if ( desc->Attribute & EFI_MEMORY_RUNTIME )
+                type = E820_RESERVED;
+            else if ( desc->Attribute & EFI_MEMORY_WB )
                 type = E820_RAM;
             else
         case EfiUnusableMemory:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:11:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:11:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433280.686248 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfoT-0000Av-DW; Tue, 01 Nov 2022 01:11:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433280.686248; Tue, 01 Nov 2022 01:11:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfoT-0000Am-Ad; Tue, 01 Nov 2022 01:11:33 +0000
Received: by outflank-mailman (input) for mailman id 433280;
 Tue, 01 Nov 2022 01:11:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoS-0000AZ-9O
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoS-0004ht-8d
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoS-0007gy-73
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=01J4a67B0js/Ca6NKEEch7pIdKc+S97V2QYQbfF4bKk=; b=VydnofSeB7BkdHydKH+KHC/EBL
	fDeENbo0R2we058vk7vV04CPN+liE6YBf9SNVA2UHQ4txEG5Q2gxgqTjSq+jedfc5mzNJtDr4hfsh
	hGXnb5ncAMAw++doMDxBQ6s0vZM1I8sOzsQaTZIJoN+AQDcmhXIHPYDN99WInXzkJ94o=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] xen/sched: fix race in RTDS scheduler
Message-Id: <E1opfoS-0007gy-73@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:11:32 +0000

commit 1f679f084fef76810762ee69a584fc1b524be0b6
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Mon Oct 31 13:33:59 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:33:59 2022 +0100

    xen/sched: fix race in RTDS scheduler
    
    When a domain gets paused the unit runnable state can change to "not
    runnable" without the scheduling lock being involved. This means that
    a specific scheduler isn't involved in this change of runnable state.
    
    In the RTDS scheduler this can result in an inconsistency in case a
    unit is losing its "runnable" capability while the RTDS scheduler's
    scheduling function is active. RTDS will remove the unit from the run
    queue, but doesn't do so for the replenish queue, leading to hitting
    an ASSERT() in replq_insert() later when the domain is unpaused again.
    
    Fix that by removing the unit from the replenish queue as well in this
    case.
    
    Fixes: 7c7b407e7772 ("xen/sched: introduce unit_runnable_state()")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Dario Faggioli <dfaggioli@suse.com>
    master commit: 73c62927f64ecb48f27d06176befdf76b879f340
    master date: 2022-10-21 12:32:23 +0200
---
 xen/common/sched/rt.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/common/sched/rt.c b/xen/common/sched/rt.c
index c24cd2ac32..ec2ca1bebc 100644
--- a/xen/common/sched/rt.c
+++ b/xen/common/sched/rt.c
@@ -1087,6 +1087,7 @@ rt_schedule(const struct scheduler *ops, struct sched_unit *currunit,
         else if ( !unit_runnable_state(snext->unit) )
         {
             q_remove(snext);
+            replq_remove(ops, snext);
             snext = rt_unit(sched_idle_unit(sched_cpu));
         }
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:11:43 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:11:43 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433281.686252 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfod-0000Ec-GA; Tue, 01 Nov 2022 01:11:43 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433281.686252; Tue, 01 Nov 2022 01:11:43 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfod-0000EU-DR; Tue, 01 Nov 2022 01:11:43 +0000
Received: by outflank-mailman (input) for mailman id 433281;
 Tue, 01 Nov 2022 01:11:42 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoc-0000EJ-CT
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoc-0004ja-Bk
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfoc-0007hO-Ay
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9udwB7iGWSXR99FLLBzSJeg6ZxB0DOpDBjIZjbpTIQ8=; b=LnFPYkNNJAQbjD5gy4esMIT+Ys
	TN8aK6+wf5Ra+tku+vzVnc8aSf/hkRvgP1e/RXm4FKrDJT2e8JhGwHFmbd+oypztJku5qFgDe8RTb
	Z4fADs9I1V0AzCg9w3o3WPlXVkiCqucfJjhWnMIcgKicT1oxlNszfErkWNmg9J8817cs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] xen/sched: fix restore_vcpu_affinity() by removing it
Message-Id: <E1opfoc-0007hO-Ay@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:11:42 +0000

commit 9c5114696c6f7773b7f3691f27aaa7a0636c916d
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Mon Oct 31 13:34:28 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:34:28 2022 +0100

    xen/sched: fix restore_vcpu_affinity() by removing it
    
    When the system is coming up after having been suspended,
    restore_vcpu_affinity() is called for each domain in order to adjust
    the vcpu's affinity settings in case a cpu didn't come to live again.
    
    The way restore_vcpu_affinity() is doing that is wrong, because the
    specific scheduler isn't being informed about a possible migration of
    the vcpu to another cpu. Additionally the migration is often even
    happening if all cpus are running again, as it is done without check
    whether it is really needed.
    
    As cpupool management is already calling cpu_disable_scheduler() for
    cpus not having come up again, and cpu_disable_scheduler() is taking
    care of eventually needed vcpu migration in the proper way, there is
    simply no need for restore_vcpu_affinity().
    
    So just remove restore_vcpu_affinity() completely, together with the
    no longer used sched_reset_affinity_broken().
    
    Fixes: 8a04eaa8ea83 ("xen/sched: move some per-vcpu items to struct sched_unit")
    Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Dario Faggioli <dfaggioli@suse.com>
    Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
    master commit: fce1f381f7388daaa3e96dbb0d67d7a3e4bb2d2d
    master date: 2022-10-24 11:16:27 +0100
---
 xen/arch/x86/acpi/power.c |  3 --
 xen/common/sched/core.c   | 78 -----------------------------------------------
 xen/include/xen/sched.h   |  1 -
 3 files changed, 82 deletions(-)

diff --git a/xen/arch/x86/acpi/power.c b/xen/arch/x86/acpi/power.c
index dd397f7130..1a7baeebe6 100644
--- a/xen/arch/x86/acpi/power.c
+++ b/xen/arch/x86/acpi/power.c
@@ -159,10 +159,7 @@ static void thaw_domains(void)
 
     rcu_read_lock(&domlist_read_lock);
     for_each_domain ( d )
-    {
-        restore_vcpu_affinity(d);
         domain_unpause(d);
-    }
     rcu_read_unlock(&domlist_read_lock);
 }
 
diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index 900aab8f66..9173cf690c 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -1188,84 +1188,6 @@ static bool sched_check_affinity_broken(const struct sched_unit *unit)
     return false;
 }
 
-static void sched_reset_affinity_broken(const struct sched_unit *unit)
-{
-    struct vcpu *v;
-
-    for_each_sched_unit_vcpu ( unit, v )
-        v->affinity_broken = false;
-}
-
-void restore_vcpu_affinity(struct domain *d)
-{
-    unsigned int cpu = smp_processor_id();
-    struct sched_unit *unit;
-
-    ASSERT(system_state == SYS_STATE_resume);
-
-    rcu_read_lock(&sched_res_rculock);
-
-    for_each_sched_unit ( d, unit )
-    {
-        spinlock_t *lock;
-        unsigned int old_cpu = sched_unit_master(unit);
-        struct sched_resource *res;
-
-        ASSERT(!unit_runnable(unit));
-
-        /*
-         * Re-assign the initial processor as after resume we have no
-         * guarantee the old processor has come back to life again.
-         *
-         * Therefore, here, before actually unpausing the domains, we should
-         * set v->processor of each of their vCPUs to something that will
-         * make sense for the scheduler of the cpupool in which they are in.
-         */
-        lock = unit_schedule_lock_irq(unit);
-
-        cpumask_and(cpumask_scratch_cpu(cpu), unit->cpu_hard_affinity,
-                    cpupool_domain_master_cpumask(d));
-        if ( cpumask_empty(cpumask_scratch_cpu(cpu)) )
-        {
-            if ( sched_check_affinity_broken(unit) )
-            {
-                sched_set_affinity(unit, unit->cpu_hard_affinity_saved, NULL);
-                sched_reset_affinity_broken(unit);
-                cpumask_and(cpumask_scratch_cpu(cpu), unit->cpu_hard_affinity,
-                            cpupool_domain_master_cpumask(d));
-            }
-
-            if ( cpumask_empty(cpumask_scratch_cpu(cpu)) )
-            {
-                /* Affinity settings of one vcpu are for the complete unit. */
-                printk(XENLOG_DEBUG "Breaking affinity for %pv\n",
-                       unit->vcpu_list);
-                sched_set_affinity(unit, &cpumask_all, NULL);
-                cpumask_and(cpumask_scratch_cpu(cpu), unit->cpu_hard_affinity,
-                            cpupool_domain_master_cpumask(d));
-            }
-        }
-
-        res = get_sched_res(cpumask_any(cpumask_scratch_cpu(cpu)));
-        sched_set_res(unit, res);
-
-        spin_unlock_irq(lock);
-
-        /* v->processor might have changed, so reacquire the lock. */
-        lock = unit_schedule_lock_irq(unit);
-        res = sched_pick_resource(unit_scheduler(unit), unit);
-        sched_set_res(unit, res);
-        spin_unlock_irq(lock);
-
-        if ( old_cpu != sched_unit_master(unit) )
-            sched_move_irqs(unit);
-    }
-
-    rcu_read_unlock(&sched_res_rculock);
-
-    domain_update_node_affinity(d);
-}
-
 /*
  * This function is used by cpu_hotplug code via cpu notifier chain
  * and from cpupools to switch schedulers on a cpu.
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 4e25627d96..bb05d167ae 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -993,7 +993,6 @@ void vcpu_set_periodic_timer(struct vcpu *v, s_time_t value);
 void sched_setup_dom0_vcpus(struct domain *d);
 int vcpu_temporary_affinity(struct vcpu *v, unsigned int cpu, uint8_t reason);
 int vcpu_set_hard_affinity(struct vcpu *v, const cpumask_t *affinity);
-void restore_vcpu_affinity(struct domain *d);
 int vcpu_affinity_domctl(struct domain *d, uint32_t cmd,
                          struct xen_domctl_vcpuaffinity *vcpuaff);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:11:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:11:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433282.686256 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfon-0000Hi-HZ; Tue, 01 Nov 2022 01:11:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433282.686256; Tue, 01 Nov 2022 01:11:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfon-0000Ha-Ey; Tue, 01 Nov 2022 01:11:53 +0000
Received: by outflank-mailman (input) for mailman id 433282;
 Tue, 01 Nov 2022 01:11:52 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfom-0000HO-Fc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:52 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfom-0004jw-Ex
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:52 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfom-0007ho-EF
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:11:52 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0MBn5y1YHMoRnAY2tejevpfddYQUtEeVSr6hfDKHCsg=; b=c3GjrizuVxrXWA39R3rSSh3L1n
	9sC56wCw5wYKQaTP0hmq3nFn27dwmc+tPLMLbBFXHfpwOzA0rAykNCFv+A3Mo+c9Gf96GPV2BfTfX
	o6IOrTc0wLCrZ2vpesxfO/IksGXGSzREocC9j0QaYbRRJ6VbA0mRq1Koizrt2wSDm+04=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] x86/shadow: drop (replace) bogus assertions
Message-Id: <E1opfom-0007ho-EF@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:11:52 +0000

commit 08bc78b4eecaef33250038f7e484bdf01ea1017c
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Mon Oct 31 13:35:06 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:35:06 2022 +0100

    x86/shadow: drop (replace) bogus assertions
    
    The addition of a call to shadow_blow_tables() from shadow_teardown()
    has resulted in the "no vcpus" related assertion becoming triggerable:
    If domain_create() fails with at least one page successfully allocated
    in the course of shadow_enable(), or if domain_create() succeeds and
    the domain is then killed without ever invoking XEN_DOMCTL_max_vcpus.
    Note that in-tree tests (test-resource and test-tsx) do exactly the
    latter of these two.
    
    The assertion's comment was bogus anyway: Shadow mode has been getting
    enabled before allocation of vCPU-s for quite some time. Convert the
    assertion to a conditional: As long as there are no vCPU-s, there's
    nothing to blow away.
    
    Fixes: e7aa55c0aab3 ("x86/p2m: free the paging memory pool preemptively")
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    
    A similar assertion/comment pair exists in _shadow_prealloc(); the
    comment is similarly bogus, and the assertion could in principle trigger
    e.g. when shadow_alloc_p2m_page() is called early enough. Replace those
    at the same time by a similar early return, here indicating failure to
    the caller (which will generally lead to the domain being crashed in
    shadow_prealloc()).
    
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Roger Pau Monné <roger.pau@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    master commit: a92dc2bb30ba65ae25d2f417677eb7ef9a6a0fef
    master date: 2022-10-24 15:46:11 +0200
---
 xen/arch/x86/mm/shadow/common.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index 8f7fddcee1..e36d49d1fc 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -942,8 +942,9 @@ static bool __must_check _shadow_prealloc(struct domain *d, unsigned int pages)
         /* No reclaim when the domain is dying, teardown will take care of it. */
         return false;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to reclaim when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return false;
 
     /* Stage one: walk the list of pinned pages, unpinning them */
     perfc_incr(shadow_prealloc_1);
@@ -1033,8 +1034,9 @@ void shadow_blow_tables(struct domain *d)
     mfn_t smfn;
     int i;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to do when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return;
 
     /* Pass one: unpin all pinned pages */
     foreach_pinned_shadow(d, sp, t)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:12:03 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:12:03 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433284.686260 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfox-0000MW-Jk; Tue, 01 Nov 2022 01:12:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433284.686260; Tue, 01 Nov 2022 01:12:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfox-0000MN-GY; Tue, 01 Nov 2022 01:12:03 +0000
Received: by outflank-mailman (input) for mailman id 433284;
 Tue, 01 Nov 2022 01:12:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfow-0000MA-J9
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfow-0004kN-IQ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfow-0007iM-HC
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Yn9+t2ZW+APYv44lir5e0jVSgfXsBwV1h3Tmshb6AK8=; b=dmO6625Sk8t+x8auXyo8n0/kp0
	x5ZWv92OKohzVZosn6eMVuleTaiA8FdJ4a/64pNAYbCl606pLmHJT0ApyrnJkqUmm2cKePJP2esOD
	dkqrgcloINH7PemaHdROuDHHfF5toTt5hjv2xIQBoAHGrIhNkw/EZjjIlyFjVPKpq8Nc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] vpci: don't assume that vpci per-device data exists unconditionally
Message-Id: <E1opfow-0007iM-HC@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:12:02 +0000

commit 6b035f4f5829eb213cb9fcbe83b5dfae05c857a6
Author:     Roger Pau Monné <roger.pau@citrix.com>
AuthorDate: Mon Oct 31 13:35:33 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:35:33 2022 +0100

    vpci: don't assume that vpci per-device data exists unconditionally
    
    It's possible for a device to be assigned to a domain but have no
    vpci structure if vpci_process_pending() failed and called
    vpci_remove_device() as a result.  The unconditional accesses done by
    vpci_{read,write}() and vpci_remove_device() to pdev->vpci would
    then trigger a NULL pointer dereference.
    
    Add checks for pdev->vpci presence in the affected functions.
    
    Fixes: 9c244fdef7 ('vpci: add header handlers')
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    master commit: 6ccb5e308ceeb895fbccd87a528a8bd24325aa39
    master date: 2022-10-26 14:55:30 +0200
---
 xen/drivers/vpci/vpci.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
index a27c9e600d..6b90e4fa32 100644
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -37,6 +37,9 @@ extern vpci_register_init_t *const __end_vpci_array[];
 
 void vpci_remove_device(struct pci_dev *pdev)
 {
+    if ( !pdev->vpci )
+        return;
+
     spin_lock(&pdev->vpci->lock);
     while ( !list_empty(&pdev->vpci->handlers) )
     {
@@ -320,7 +323,7 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, unsigned int size)
 
     /* Find the PCI dev matching the address. */
     pdev = pci_get_pdev_by_domain(d, sbdf.seg, sbdf.bus, sbdf.devfn);
-    if ( !pdev )
+    if ( !pdev || !pdev->vpci )
         return vpci_read_hw(sbdf, reg, size);
 
     spin_lock(&pdev->vpci->lock);
@@ -430,7 +433,7 @@ void vpci_write(pci_sbdf_t sbdf, unsigned int reg, unsigned int size,
      * Passthrough everything that's not trapped.
      */
     pdev = pci_get_pdev_by_domain(d, sbdf.seg, sbdf.bus, sbdf.devfn);
-    if ( !pdev )
+    if ( !pdev || !pdev->vpci )
     {
         vpci_write_hw(sbdf, reg, size, data);
         return;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:12:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:12:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433285.686264 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfp7-0000Ox-Ko; Tue, 01 Nov 2022 01:12:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433285.686264; Tue, 01 Nov 2022 01:12:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfp7-0000Op-I8; Tue, 01 Nov 2022 01:12:13 +0000
Received: by outflank-mailman (input) for mailman id 433285;
 Tue, 01 Nov 2022 01:12:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfp6-0000Oh-MF
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfp6-0004kR-LT
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfp6-0007iu-Kb
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=7f954o1DYVWt2YCefb4Xzrqjuj21U2o6NH9qyczUMMI=; b=tJW1XQunmWTy307fJ42YQ4BRxu
	64wn3VTDRm1jlXmFDTG0g2K2yadF5rvNNF3ENqWQI5eUKzDWq+eN/vBABc56BAeHOxQWCL5Avv1NZ
	vxy8XX7Psi313BaKEVxFfxN4ECwoA8OG/PZBUv3F//CVskCtcHJQcg1IgWBr3k6sTFsA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] vpci/msix: remove from table list on detach
Message-Id: <E1opfp6-0007iu-Kb@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:12:12 +0000

commit bff4c4457950abb498270d921d728f654876f944
Author:     Roger Pau Monné <roger.pau@citrix.com>
AuthorDate: Mon Oct 31 13:35:59 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:35:59 2022 +0100

    vpci/msix: remove from table list on detach
    
    Teardown of MSIX vPCI related data doesn't currently remove the MSIX
    device data from the list of MSIX tables handled by the domain,
    leading to a use-after-free of the data in the msix structure.
    
    Remove the structure from the list before freeing in order to solve
    it.
    
    Reported-by: Jan Beulich <jbeulich@suse.com>
    Fixes: d6281be9d0 ('vpci/msix: add MSI-X handlers')
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    master commit: c14aea137eab29eb9c30bfad745a00c65ad21066
    master date: 2022-10-26 14:56:58 +0200
---
 xen/drivers/vpci/vpci.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
index 6b90e4fa32..75edbbee40 100644
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -51,8 +51,12 @@ void vpci_remove_device(struct pci_dev *pdev)
         xfree(r);
     }
     spin_unlock(&pdev->vpci->lock);
-    if ( pdev->vpci->msix && pdev->vpci->msix->pba )
-        iounmap(pdev->vpci->msix->pba);
+    if ( pdev->vpci->msix )
+    {
+        list_del(&pdev->vpci->msix->next);
+        if ( pdev->vpci->msix->pba )
+            iounmap(pdev->vpci->msix->pba);
+    }
     xfree(pdev->vpci->msix);
     xfree(pdev->vpci->msi);
     xfree(pdev->vpci);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:12:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:12:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433286.686268 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpH-0000SF-NQ; Tue, 01 Nov 2022 01:12:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433286.686268; Tue, 01 Nov 2022 01:12:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpH-0000S7-Jc; Tue, 01 Nov 2022 01:12:23 +0000
Received: by outflank-mailman (input) for mailman id 433286;
 Tue, 01 Nov 2022 01:12:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpG-0000Rt-Pu
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpG-0004kY-PI
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpG-0007jM-Nl
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=XFsM3mMkd39fUKE0sztkdY7GWRJUa3z6YObVBg9O2A8=; b=yaApmXZ/Vj6i9qtEo1EssVqDfK
	RU7xunTIvEdzEzukU81aHqfpLQevxBOkrul329QMa1DZh66LhDitv0L8nZALWzHmRuPZvK/fKtxvF
	QDAzQEBGl6HBjUTsE6mPm0FUTy73+ALeNbLy6EBRNozOcHRuVYR1+ad7fWffX+NrDBQw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] x86: also zap secondary time area handles during soft reset
Message-Id: <E1opfpG-0007jM-Nl@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:12:22 +0000

commit 9b8b65c827169eca2d0e500150009ac0f857d455
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Mon Oct 31 13:36:25 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:36:25 2022 +0100

    x86: also zap secondary time area handles during soft reset
    
    Just like domain_soft_reset() properly zaps runstate area handles, the
    secondary time area ones also need discarding to prevent guest memory
    corruption once the guest is re-started.
    
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
    master commit: b80d4f8d2ea6418e32fb4f20d1304ace6d6566e3
    master date: 2022-10-27 11:49:09 +0200
---
 xen/arch/x86/domain.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index ce6ddcf313..e9b8ed4c96 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -927,6 +927,7 @@ int arch_domain_soft_reset(struct domain *d)
     struct page_info *page = virt_to_page(d->shared_info), *new_page;
     int ret = 0;
     struct domain *owner;
+    struct vcpu *v;
     mfn_t mfn;
     gfn_t gfn;
     p2m_type_t p2mt;
@@ -1006,7 +1007,12 @@ int arch_domain_soft_reset(struct domain *d)
                "Failed to add a page to replace %pd's shared_info frame %"PRI_gfn"\n",
                d, gfn_x(gfn));
         free_domheap_page(new_page);
+        goto exit_put_gfn;
     }
+
+    for_each_vcpu ( d, v )
+        set_xen_guest_handle(v->arch.time_info_guest, NULL);
+
  exit_put_gfn:
     put_gfn(d, gfn_x(gfn));
  exit_put_page:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:12:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:12:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433287.686272 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpR-0000VS-O3; Tue, 01 Nov 2022 01:12:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433287.686272; Tue, 01 Nov 2022 01:12:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpR-0000VK-LD; Tue, 01 Nov 2022 01:12:33 +0000
Received: by outflank-mailman (input) for mailman id 433287;
 Tue, 01 Nov 2022 01:12:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpQ-0000VA-Sz
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpQ-0004l3-SJ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpQ-0007jn-RX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=kr6Le0+N6gbdpBGm/41Qmd4qfIGJQ9Uui25u0UlDzeI=; b=cey+WMgfCjqOoNfScsEq1CPVQQ
	ue+UYoPLL//nEmbE7D87+C/KPIvuC7L4+Tp80mCC0l3WgZgao3RtN9ISwgXCHJglRa14d0INZNk+c
	jX7iKoyW0yJTQH3dX51eTWR6WaLHsJdbxr3TfGBCBCyr6N19yMI7EpwScFQRlTkbq3Ic=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] common: map_vcpu_info() wants to unshare the underlying page
Message-Id: <E1opfpQ-0007jn-RX@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:12:32 +0000

commit 317894fa6a067a7903199bc5c1e3e06a0436caf8
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Mon Oct 31 13:36:50 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:36:50 2022 +0100

    common: map_vcpu_info() wants to unshare the underlying page
    
    Not passing P2M_UNSHARE to get_page_from_gfn() means there won't even be
    an attempt to unshare the referenced page, without any indication to the
    caller (e.g. -EAGAIN). Note that guests have no direct control over
    which of their pages are shared (or paged out), and hence they have no
    way to make sure all on their own that the subsequent obtaining of a
    writable type reference can actually succeed.
    
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    master commit: 48980cf24d5cf41fd644600f99c753419505e735
    master date: 2022-10-28 11:38:32 +0200
---
 xen/common/domain.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index 17cc32fde3..0fb7f9a622 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1454,7 +1454,7 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
     if ( (v != current) && !(v->pause_flags & VPF_down) )
         return -EINVAL;
 
-    page = get_page_from_gfn(d, gfn, NULL, P2M_ALLOC);
+    page = get_page_from_gfn(d, gfn, NULL, P2M_UNSHARE);
     if ( !page )
         return -EINVAL;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:12:43 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:12:43 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433288.686276 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpb-0000YV-PN; Tue, 01 Nov 2022 01:12:43 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433288.686276; Tue, 01 Nov 2022 01:12:43 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpb-0000YN-Mj; Tue, 01 Nov 2022 01:12:43 +0000
Received: by outflank-mailman (input) for mailman id 433288;
 Tue, 01 Nov 2022 01:12:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpa-0000YF-Vz
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpa-0004l9-VC
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpa-0007kE-US
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=VwP9nOEGxLJ1ojzDMbIzmTOm7TDAxos6p2WvYNutDOo=; b=iSUqEiRgxceuzCGjDNNO2DZTwX
	s+1SD5eVMvCpIaiBiCJgUEDHwrvqgCDt4IrIzEnir+JRNOjjuuTB+MqxBC/Y0FsFJ7CUi4gTmh5JK
	pD0e8HlJTW+Dd56vcfhfUw1lBvN72fwx2NrAyFVKQZmKvG5BPtPOvF+hIm0p2c2pg/OU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] x86/pv-shim: correctly ignore empty onlining requests
Message-Id: <E1opfpa-0007kE-US@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:12:42 +0000

commit a46f01fad17173afe3809ac1980cbe4b67a9a8b5
Author:     Igor Druzhinin <igor.druzhinin@citrix.com>
AuthorDate: Mon Oct 31 13:37:17 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:37:17 2022 +0100

    x86/pv-shim: correctly ignore empty onlining requests
    
    Mem-op requests may have zero extents. Such requests need treating as
    no-ops. pv_shim_online_memory(), however, would have tried to take 2³²-1
    order-sized pages from its balloon list (to then populate them),
    typically ending when the entire set of ballooned pages of this order
    was consumed.
    
    Note that pv_shim_offline_memory() does not have such an issue.
    
    Fixes: b2245acc60c3 ("xen/pvshim: memory hotplug")
    Signed-off-by: Igor Druzhinin <igor.druzhinin@citrix.com>
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    master commit: 9272225ca72801fd9fa5b268a2d1c5adebd19cd9
    master date: 2022-10-28 15:47:59 +0200
---
 xen/arch/x86/pv/shim.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/xen/arch/x86/pv/shim.c b/xen/arch/x86/pv/shim.c
index b4e83e0778..104357e2c3 100644
--- a/xen/arch/x86/pv/shim.c
+++ b/xen/arch/x86/pv/shim.c
@@ -922,6 +922,9 @@ void pv_shim_online_memory(unsigned int nr, unsigned int order)
     struct page_info *page, *tmp;
     PAGE_LIST_HEAD(list);
 
+    if ( !nr )
+        return;
+
     spin_lock(&balloon_lock);
     page_list_for_each_safe ( page, tmp, &balloon )
     {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:12:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:12:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433289.686280 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpl-0000c1-SK; Tue, 01 Nov 2022 01:12:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433289.686280; Tue, 01 Nov 2022 01:12:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpl-0000bt-Pb; Tue, 01 Nov 2022 01:12:53 +0000
Received: by outflank-mailman (input) for mailman id 433289;
 Tue, 01 Nov 2022 01:12:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpl-0000bl-2O
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpl-0004lD-1l
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpl-0007kp-19
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:12:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=uD+caH3rnq4+Lzbw0Vrky15bJdrrf5o6osEdbJGDruU=; b=d+iLlIFzwBZqPBpSBmiTZ0IXtU
	IfTuACRtOkwHKhF6hbSkiSjWVnzIEEAzRBK0QIvXJQBQkFiESqPgP1LPhaJfRsFEj2WWT4K/tKYmC
	NIZ7tVSfxJtchPuUe/gj1tm1O1KbcXfMl5SpVx/TgXYNF5WZaO+oj1zzhe/a9Py2gZyA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] x86/pv-shim: correct ballooning up for compat guests
Message-Id: <E1opfpl-0007kp-19@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:12:53 +0000

commit b68e3fda8a76fb3ab582b5633727ac5545e4e8b9
Author:     Igor Druzhinin <igor.druzhinin@citrix.com>
AuthorDate: Mon Oct 31 13:37:42 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:37:42 2022 +0100

    x86/pv-shim: correct ballooning up for compat guests
    
    The compat layer for multi-extent memory ops may need to split incoming
    requests. Since the guest handles in the interface structures may not be
    altered, it does so by leveraging do_memory_op()'s continuation
    handling: It hands on non-initial requests with a non-zero start extent,
    with the (native) handle suitably adjusted down. As a result
    do_memory_op() sees only the first of potentially several requests with
    start extent being zero. It's only that case when the function would
    issue a call to pv_shim_online_memory(), yet the range then covers only
    the first sub-range that results from the split.
    
    Address that breakage by making a complementary call to
    pv_shim_online_memory() in compat layer.
    
    Fixes: b2245acc60c3 ("xen/pvshim: memory hotplug")
    Signed-off-by: Igor Druzhinin <igor.druzhinin@citrix.com>
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    master commit: a0bfdd201ea12aa5679bb8944d63a4e0d3c23160
    master date: 2022-10-28 15:48:50 +0200
---
 xen/common/compat/memory.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/xen/common/compat/memory.c b/xen/common/compat/memory.c
index c43fa97cf1..a0e0562a40 100644
--- a/xen/common/compat/memory.c
+++ b/xen/common/compat/memory.c
@@ -7,6 +7,7 @@ EMIT_FILE;
 #include <xen/event.h>
 #include <xen/mem_access.h>
 #include <asm/current.h>
+#include <asm/guest.h>
 #include <compat/memory.h>
 
 #define xen_domid_t domid_t
@@ -146,7 +147,10 @@ int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) compat)
                 nat.rsrv->nr_extents = end_extent;
                 ++split;
             }
-
+           /* Avoid calling pv_shim_online_memory() when in a continuation. */
+           if ( pv_shim && op != XENMEM_decrease_reservation && !start_extent )
+               pv_shim_online_memory(cmp.rsrv.nr_extents - nat.rsrv->nr_extents,
+                                     cmp.rsrv.extent_order);
             break;
 
         case XENMEM_exchange:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 01:13:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 01:13:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.433290.686283 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpw-0000el-U2; Tue, 01 Nov 2022 01:13:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 433290.686283; Tue, 01 Nov 2022 01:13:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opfpw-0000ed-RF; Tue, 01 Nov 2022 01:13:04 +0000
Received: by outflank-mailman (input) for mailman id 433290;
 Tue, 01 Nov 2022 01:13:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpv-0000eW-5U
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:13:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpv-0004lU-4q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:13:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opfpv-0007lj-43
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 01:13:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5/w2LE0tkQ1Zo3zvArKnc5k44JbwRI0OG8YTanM8xXU=; b=WavdTSzQg3M0qMIDdgiAKyztxV
	41n7BFtd4PmKpZJ9+vKcrNDwXcatcUNb2ZgXRrd/2tqiGVaQgKxMpu2jjuJ2FQNFzcss/dlWjWUjq
	rb/BMAnL0bYus0f8/+oSJZs7OzaI7lUnILGrGRfkD+jOGaaaAEW9DvTK3h1ed3KBXZsQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] x86/pv-shim: correct ballooning down for compat guests
Message-Id: <E1opfpv-0007lj-43@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 01:13:03 +0000

commit ddab5b1e001366258c0bfc7d5995b9d548e6042b
Author:     Igor Druzhinin <igor.druzhinin@citrix.com>
AuthorDate: Mon Oct 31 13:38:05 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Oct 31 13:38:05 2022 +0100

    x86/pv-shim: correct ballooning down for compat guests
    
    The compat layer for multi-extent memory ops may need to split incoming
    requests. Since the guest handles in the interface structures may not be
    altered, it does so by leveraging do_memory_op()'s continuation
    handling: It hands on non-initial requests with a non-zero start extent,
    with the (native) handle suitably adjusted down. As a result
    do_memory_op() sees only the first of potentially several requests with
    start extent being zero. In order to be usable as overall result, the
    function accumulates args.nr_done, i.e. it initialized the field with
    the start extent. Therefore non-initial requests resulting from the
    split would pass too large a number into pv_shim_offline_memory().
    
    Address that breakage by always calling pv_shim_offline_memory()
    regardless of current hypercall preemption status, with a suitably
    adjusted first argument. Note that this is correct also for the native
    guest case: We now simply "commit" what was completed right away, rather
    than at the end of a series of preemption/re-start cycles. In fact this
    improves overall preemption behavior: There's no longer a potentially
    big chunk of work done non-preemptively at the end of the last
    "iteration".
    
    Fixes: b2245acc60c3 ("xen/pvshim: memory hotplug")
    Signed-off-by: Igor Druzhinin <igor.druzhinin@citrix.com>
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    master commit: 1d7fbc535d1d37bdc2cc53ede360b0f6651f7de1
    master date: 2022-10-28 15:49:33 +0200
---
 xen/common/memory.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/xen/common/memory.c b/xen/common/memory.c
index 95b2b934e4..a958d94ac3 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -1407,22 +1407,17 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
 
         rc = args.nr_done;
 
-        if ( args.preempted )
-            return hypercall_create_continuation(
-                __HYPERVISOR_memory_op, "lh",
-                op | (rc << MEMOP_EXTENT_SHIFT), arg);
-
 #ifdef CONFIG_X86
         if ( pv_shim && op == XENMEM_decrease_reservation )
-            /*
-             * Only call pv_shim_offline_memory when the hypercall has
-             * finished. Note that nr_done is used to cope in case the
-             * hypercall has failed and only part of the extents where
-             * processed.
-             */
-            pv_shim_offline_memory(args.nr_done, args.extent_order);
+            pv_shim_offline_memory(args.nr_done - start_extent,
+                                   args.extent_order);
 #endif
 
+        if ( args.preempted )
+           return hypercall_create_continuation(
+                __HYPERVISOR_memory_op, "lh",
+                op | (rc << MEMOP_EXTENT_SHIFT), arg);
+
         break;
 
     case XENMEM_exchange:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:11:11 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:11:11 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434605.686900 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr2o-0000Cv-SB; Tue, 01 Nov 2022 13:11:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434605.686900; Tue, 01 Nov 2022 13:11:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr2o-0000Co-OM; Tue, 01 Nov 2022 13:11:06 +0000
Received: by outflank-mailman (input) for mailman id 434605;
 Tue, 01 Nov 2022 13:11:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr2n-0000Ci-ET
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr2n-0006yn-B0
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr2n-0003gc-9E
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=QM2PmoMJPSEIeIsTgqeRG7KubgB35vhP7pdGAuUHlXw=; b=aoBqs4O4WqT0JrhFKnn3yY3c/2
	sdiHk3rfgP9h9ptsG30QCo+DPWcBpwQl2rQD8pYjsYthVvBUn6SoAAEwNe/fmwA14TA2lsvI7Qt3x
	4r6XJQB5T8t3tiEw7DujPlM1c9WfgjW/9dCsgU46OJPbFXCD7lPwU8Uyrtj7+V3woDww=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] x86/vmx: Revert "VMX: use a single, global APIC access page"
Message-Id: <E1opr2n-0003gc-9E@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:11:05 +0000

commit 3b5beaf49033cddf4b2cc4e4d391b966f4203471
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Wed Aug 24 14:16:44 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    x86/vmx: Revert "VMX: use a single, global APIC access page"
    
    The claim "No accesses would ever go to this page." is false.  A consequence
    of how Intel's APIC Acceleration works, and Xen's choice to have per-domain
    P2Ms (rather than per-vCPU P2Ms) means that the APIC page is fully read-write
    to any vCPU which is not in xAPIC mode.
    
    This reverts commit 58850b9074d3e7affdf3bc94c84e417ecfa4d165.
    
    This is XSA-412 / CVE-2022-42327.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/hvm/vmx/vmx.c              | 59 ++++++++++++++++++++++++---------
 xen/arch/x86/include/asm/hvm/vmx/vmcs.h |  1 +
 xen/arch/x86/include/asm/mm.h           | 20 +----------
 xen/arch/x86/mm/shadow/set.c            |  8 -----
 xen/arch/x86/mm/shadow/types.h          |  7 ----
 5 files changed, 46 insertions(+), 49 deletions(-)

diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 17e103188a..e624b415c9 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -66,7 +66,8 @@ boolean_param("force-ept", opt_force_ept);
 static void cf_check vmx_ctxt_switch_from(struct vcpu *v);
 static void cf_check vmx_ctxt_switch_to(struct vcpu *v);
 
-static int alloc_vlapic_mapping(void);
+static int  vmx_alloc_vlapic_mapping(struct domain *d);
+static void vmx_free_vlapic_mapping(struct domain *d);
 static void vmx_install_vlapic_mapping(struct vcpu *v);
 static void cf_check vmx_update_guest_cr(
     struct vcpu *v, unsigned int cr, unsigned int flags);
@@ -79,8 +80,6 @@ static int cf_check vmx_msr_write_intercept(
     unsigned int msr, uint64_t msr_content);
 static void cf_check vmx_invlpg(struct vcpu *v, unsigned long linear);
 
-static mfn_t __read_mostly apic_access_mfn = INVALID_MFN_INITIALIZER;
-
 /* Values for domain's ->arch.hvm_domain.pi_ops.flags. */
 #define PI_CSW_FROM (1u << 0)
 #define PI_CSW_TO   (1u << 1)
@@ -404,6 +403,7 @@ static int cf_check vmx_domain_initialise(struct domain *d)
         .to   = vmx_ctxt_switch_to,
         .tail = vmx_do_resume,
     };
+    int rc;
 
     d->arch.ctxt_switch = &csw;
 
@@ -413,15 +413,24 @@ static int cf_check vmx_domain_initialise(struct domain *d)
      */
     d->arch.hvm.vmx.exec_sp = is_hardware_domain(d) || opt_ept_exec_sp;
 
+    if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 )
+        return rc;
+
     return 0;
 }
 
+static void cf_check vmx_domain_relinquish_resources(struct domain *d)
+{
+    vmx_free_vlapic_mapping(d);
+}
+
 static void cf_check domain_creation_finished(struct domain *d)
 {
     gfn_t gfn = gaddr_to_gfn(APIC_DEFAULT_PHYS_BASE);
+    mfn_t apic_access_mfn = d->arch.hvm.vmx.apic_access_mfn;
     bool ipat;
 
-    if ( mfn_eq(apic_access_mfn, INVALID_MFN) )
+    if ( mfn_eq(apic_access_mfn, _mfn(0)) )
         return;
 
     ASSERT(epte_get_entry_emt(d, gfn, apic_access_mfn, 0, &ipat,
@@ -2510,6 +2519,7 @@ static struct hvm_function_table __initdata_cf_clobber vmx_function_table = {
     .cpu_up_prepare       = vmx_cpu_up_prepare,
     .cpu_dead             = vmx_cpu_dead,
     .domain_initialise    = vmx_domain_initialise,
+    .domain_relinquish_resources = vmx_domain_relinquish_resources,
     .domain_creation_finished = domain_creation_finished,
     .vcpu_initialise      = vmx_vcpu_initialise,
     .vcpu_destroy         = vmx_vcpu_destroy,
@@ -2760,7 +2770,7 @@ const struct hvm_function_table * __init start_vmx(void)
 {
     set_in_cr4(X86_CR4_VMXE);
 
-    if ( vmx_vmcs_init() || alloc_vlapic_mapping() )
+    if ( vmx_vmcs_init() )
     {
         printk("VMX: failed to initialise.\n");
         return NULL;
@@ -3331,36 +3341,55 @@ gp_fault:
     return X86EMUL_EXCEPTION;
 }
 
-static int __init alloc_vlapic_mapping(void)
+static int vmx_alloc_vlapic_mapping(struct domain *d)
 {
     struct page_info *pg;
     mfn_t mfn;
 
-    if ( !cpu_has_vmx_virtualize_apic_accesses )
+    if ( !has_vlapic(d) || !cpu_has_vmx_virtualize_apic_accesses )
         return 0;
 
-    pg = alloc_domheap_page(NULL, 0);
+    pg = alloc_domheap_page(d, MEMF_no_refcount);
     if ( !pg )
         return -ENOMEM;
 
-    /*
-     * Signal to shadow code that this page cannot be refcounted. This also
-     * makes epte_get_entry_emt() recognize this page as "special".
-     */
-    page_suppress_refcounting(pg);
+    if ( !get_page_and_type(pg, d, PGT_writable_page) )
+    {
+        /*
+         * The domain can't possibly know about this page yet, so failure
+         * here is a clear indication of something fishy going on.
+         */
+        domain_crash(d);
+        return -ENODATA;
+    }
 
     mfn = page_to_mfn(pg);
     clear_domain_page(mfn);
-    apic_access_mfn = mfn;
+    d->arch.hvm.vmx.apic_access_mfn = mfn;
 
     return 0;
 }
 
+static void vmx_free_vlapic_mapping(struct domain *d)
+{
+    mfn_t mfn = d->arch.hvm.vmx.apic_access_mfn;
+
+    d->arch.hvm.vmx.apic_access_mfn = _mfn(0);
+    if ( !mfn_eq(mfn, _mfn(0)) )
+    {
+        struct page_info *pg = mfn_to_page(mfn);
+
+        put_page_alloc_ref(pg);
+        put_page_and_type(pg);
+    }
+}
+
 static void vmx_install_vlapic_mapping(struct vcpu *v)
 {
+    mfn_t apic_access_mfn = v->domain->arch.hvm.vmx.apic_access_mfn;
     paddr_t virt_page_ma, apic_page_ma;
 
-    if ( mfn_eq(apic_access_mfn, INVALID_MFN) )
+    if ( mfn_eq(apic_access_mfn, _mfn(0)) )
         return;
 
     ASSERT(cpu_has_vmx_virtualize_apic_accesses);
diff --git a/xen/arch/x86/include/asm/hvm/vmx/vmcs.h b/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
index 9119aa8536..75f9928abf 100644
--- a/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
+++ b/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
@@ -58,6 +58,7 @@ struct ept_data {
 #define _VMX_DOMAIN_PML_ENABLED    0
 #define VMX_DOMAIN_PML_ENABLED     (1ul << _VMX_DOMAIN_PML_ENABLED)
 struct vmx_domain {
+    mfn_t apic_access_mfn;
     /* VMX_DOMAIN_* */
     unsigned int status;
 
diff --git a/xen/arch/x86/include/asm/mm.h b/xen/arch/x86/include/asm/mm.h
index 0fc826de46..d723c7c38f 100644
--- a/xen/arch/x86/include/asm/mm.h
+++ b/xen/arch/x86/include/asm/mm.h
@@ -83,7 +83,7 @@
 #define PGC_state_offlined  PG_mask(2, 6)
 #define PGC_state_free      PG_mask(3, 6)
 #define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
-/* Page is not reference counted (see below for caveats) */
+/* Page is not reference counted */
 #define _PGC_extra        PG_shift(7)
 #define PGC_extra         PG_mask(1, 7)
 
@@ -375,24 +375,6 @@ void zap_ro_mpt(mfn_t mfn);
 
 bool is_iomem_page(mfn_t mfn);
 
-/*
- * Pages with no owner which may get passed to functions wanting to
- * refcount them can be marked PGC_extra to bypass this refcounting (which
- * would fail due to the lack of an owner).
- *
- * (For pages with owner PGC_extra has different meaning.)
- */
-static inline void page_suppress_refcounting(struct page_info *pg)
-{
-   ASSERT(!page_get_owner(pg));
-   pg->count_info |= PGC_extra;
-}
-
-static inline bool page_refcounting_suppressed(const struct page_info *pg)
-{
-    return !page_get_owner(pg) && (pg->count_info & PGC_extra);
-}
-
 struct platform_bad_page {
     unsigned long mfn;
     unsigned int order;
diff --git a/xen/arch/x86/mm/shadow/set.c b/xen/arch/x86/mm/shadow/set.c
index 87e9c6eeb2..bd6c68b547 100644
--- a/xen/arch/x86/mm/shadow/set.c
+++ b/xen/arch/x86/mm/shadow/set.c
@@ -101,14 +101,6 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type)
         owner = page_get_owner(pg);
     }
 
-    /*
-     * Check whether refcounting is suppressed on this page. For example,
-     * VMX'es APIC access MFN is just a surrogate page.  It doesn't actually
-     * get accessed, and hence there's no need to refcount it.
-     */
-    if ( pg && page_refcounting_suppressed(pg) )
-        return 0;
-
     if ( owner == dom_io )
         owner = NULL;
 
diff --git a/xen/arch/x86/mm/shadow/types.h b/xen/arch/x86/mm/shadow/types.h
index 6970e7d6ea..814a401853 100644
--- a/xen/arch/x86/mm/shadow/types.h
+++ b/xen/arch/x86/mm/shadow/types.h
@@ -276,16 +276,9 @@ int shadow_set_l4e(struct domain *d, shadow_l4e_t *sl4e,
 static void inline
 shadow_put_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
 {
-    mfn_t mfn = shadow_l1e_get_mfn(sl1e);
-
     if ( !shadow_mode_refcounts(d) )
         return;
 
-    if ( mfn_valid(mfn) &&
-         /* See the respective comment in shadow_get_page_from_l1e(). */
-         page_refcounting_suppressed(mfn_to_page(mfn)) )
-        return;
-
     put_page_from_l1e(sl1e, d);
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:11:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:11:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434606.686902 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr2y-0000Eb-TJ; Tue, 01 Nov 2022 13:11:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434606.686902; Tue, 01 Nov 2022 13:11:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr2y-0000ET-QH; Tue, 01 Nov 2022 13:11:16 +0000
Received: by outflank-mailman (input) for mailman id 434606;
 Tue, 01 Nov 2022 13:11:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr2x-0000EI-FG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr2x-0006yx-ET
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr2x-0003h1-DS
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=UhkBglR9e4uoZrosvjA9b1baxgyMvCDHGGOAIgIoFCc=; b=HtZHVAiFQ+RMrQs0L9h0Wvp2S/
	AJ6cKnNdXE+C5QZKdyMM1WbdxB8NVvmz7YKBUd1xAwpEP3Z9DaKxtrO8i9sZ4ysdMjxSI0IVsw3s1
	WHkTyXagLjTJt/NK4TkIYqIVzGj6sgQHx88aOEjyYdy0ddr9PvhXuXPxeNKNELCHWoUQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1opr2x-0003h1-DS@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:11:15 +0000

commit 1cd3cc7ea27cda7640a8d895e09617b61c265697
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8867f93431..c30d14cbf2 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1084,9 +1084,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -1095,7 +1094,7 @@ static int destroy_node(void *_node)
 	set_tdb_key(node->name, &key);
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -1104,7 +1103,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1126,23 +1126,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:11:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:11:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434607.686906 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr38-0000HY-VC; Tue, 01 Nov 2022 13:11:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434607.686906; Tue, 01 Nov 2022 13:11:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr38-0000HP-Rp; Tue, 01 Nov 2022 13:11:26 +0000
Received: by outflank-mailman (input) for mailman id 434607;
 Tue, 01 Nov 2022 13:11:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr37-0000H0-Id
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr37-0006zF-Hv
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr37-0003hh-H3
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=VOIG952Ibz2WGRhAEf0S78z6p1EENtfFNwDIgtyAsX8=; b=CID1TnO8JIkvYglorxa4Ozu4Op
	aJVk/GTtNM4cDwfCFjJ5wqjvhjZ2oxPInUru//2JLOLXFCnhs9MBS5HJWxfYjDbsk4VlwX4moJlip
	GGMiJf1M3NxLh2u+1yA//E2LVuy1smjjhwk/baju9Ki6nf8PkJTXn0hJnqO7+UE5UuB8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1opr37-0003hh-H3@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:11:25 +0000

commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
---
 tools/xenstore/xenstored_core.c        | 23 +++++++++++++++--------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c30d14cbf2..55b79e4c03 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -562,15 +562,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 unsigned int perm_for_conn(struct connection *conn,
@@ -1086,16 +1088,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	set_tdb_key(node->name, &key);
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 742812a974..7d0fe77e79 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -155,6 +155,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd07fb0f21..faf6c930e4 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:11:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:11:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434608.686910 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3I-0000KL-WF; Tue, 01 Nov 2022 13:11:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434608.686910; Tue, 01 Nov 2022 13:11:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3I-0000KD-TN; Tue, 01 Nov 2022 13:11:36 +0000
Received: by outflank-mailman (input) for mailman id 434608;
 Tue, 01 Nov 2022 13:11:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3H-0000K2-Lq
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3H-0006zm-L9
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3H-0003iU-KD
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=oskCP0csc4JiTvmL2QxIAP/cBaBKYp22Y2sxk7d0aI8=; b=Oid9scBNkTRuUOKSDb+dV1Xohx
	Dt5W2NSidLfC24rwi6cnzWPOyyhDsrgy+ZrgetgwskqSe0wX5h1dKuz9anP85YQOgneyrjDiuRv7D
	jXjcGTCKktG6C3ko4L8g61bnM23BY5xpSNTLQcHBcLf4i+sBqiDwl14fZlsEumpbrPwc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: split up send_reply()
Message-Id: <E1opr3H-0003iU-KD@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:11:35 +0000

commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 39 ++++-----------------
 3 files changed, 52 insertions(+), 62 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 55b79e4c03..ed742d9dfc 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -763,49 +763,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -813,8 +796,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 7d0fe77e79..99a0373944 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -187,6 +187,7 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index aca0a71bad..99a2c266b2 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -85,35 +85,6 @@ static const char *get_watch_path(const struct watch *watch, const char *name)
 	return path;
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
-{
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
-
-	name = get_watch_path(watch, name);
-
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
-}
-
 /*
  * Check permissions of a specific watch to fire:
  * Either the node itself or its parent have to be readable by the connection
@@ -190,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -292,7 +267,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:11:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:11:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434609.686914 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3T-0000Na-3v; Tue, 01 Nov 2022 13:11:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434609.686914; Tue, 01 Nov 2022 13:11:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3T-0000NT-1M; Tue, 01 Nov 2022 13:11:47 +0000
Received: by outflank-mailman (input) for mailman id 434609;
 Tue, 01 Nov 2022 13:11:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3R-0000N6-P9
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3R-00071T-OW
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3R-0003iv-Nc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NJeuVdueD/IqetRNMBSb2bJ0UpaEyV90GWGBEemaXVo=; b=uqNslgih6z16sjXvyDuAg06i2u
	EtvE3+hpsK9UYmVK26BAnc6r9BUeC1VBb6l+QKC2bwq1JUZNUid3BArtZKKSoaKvjMPJjM5siuYcM
	h8m3TpRCszV/BCLFI8Ydc0MOrSg3ADEmsb7lrzAmYsTZQKKFSrM+2lf8qZEguUMho9jU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1opr3R-0003iv-Nc@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:11:45 +0000

commit ead062a68a9c201a95488e84750a70a107f7b317
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 18 ++++++++++++++++--
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c | 15 ++-------------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ed742d9dfc..61fc368e8c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -207,6 +207,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -250,8 +265,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 99a0373944..c9ea796185 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -271,6 +271,8 @@ int remember_string(struct hashtable *hash, const char *str);
 
 void set_tdb_key(const char *name, TDB_DATA *key);
 
+void conn_free_buffered_data(struct connection *conn);
+
 const char *dump_state_global(FILE *fp);
 const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 				     struct xs_state_connection *sc);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index ead4c237d2..de349e2a77 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -411,15 +411,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
@@ -436,8 +431,6 @@ static void domain_conn_reset(struct domain *domain)
  */
 void ignore_connection(struct connection *conn, unsigned int err)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored, reason %u\n", conn, err);
 
 	if (conn->domain && conn->domain->interface)
@@ -446,11 +439,7 @@ void ignore_connection(struct connection *conn, unsigned int err)
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:11:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:11:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434610.686918 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3d-0000QM-5s; Tue, 01 Nov 2022 13:11:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434610.686918; Tue, 01 Nov 2022 13:11:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3d-0000QE-39; Tue, 01 Nov 2022 13:11:57 +0000
Received: by outflank-mailman (input) for mailman id 434610;
 Tue, 01 Nov 2022 13:11:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3b-0000Pt-SB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3b-00071g-Rc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3b-0003jM-Qt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:11:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=vydqPA4YkMcTvQxgv4U3y5wUE3XifYXT+ZF7k6BVsYg=; b=qMKKkD2pfdhMPvg66+JmAc84jc
	AVFzhfSV4pvAKeowGe7yzYFqorsxJoXTInTmBnbtkqz9HuJt1X5WIhaiBFl2GrANVvLNjeGsmVZtU
	Q39Y+zzeK3TPIcQxHJIBNmYVR8bzAZv/N23IhlamoW+bxcJWI+Uc9quwgC5Fg40D/gCw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: reduce number of watch events
Message-Id: <E1opr3b-0003jM-Qt@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:11:55 +0000

commit 3a96013a3e17baa07410b1b9776225d1d9a74297
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 61fc368e8c..b9a0ff5e05 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1291,7 +1291,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1303,7 +1303,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1315,7 +1315,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1341,13 +1346,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index faf6c930e4..54432907fc 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -323,6 +327,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 99a2c266b2..205d9d8ea1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:12:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:12:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434611.686922 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3n-0000UD-7a; Tue, 01 Nov 2022 13:12:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434611.686922; Tue, 01 Nov 2022 13:12:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3n-0000U5-4d; Tue, 01 Nov 2022 13:12:07 +0000
Received: by outflank-mailman (input) for mailman id 434611;
 Tue, 01 Nov 2022 13:12:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3l-0000Ts-Vc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3l-000723-Ur
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3l-0003k2-U3
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=/JLvoRGrBt0BH7goFlXoPo8+FTmBT1C4GjJP0mmY26U=; b=I0ucmdCIgipItKTY89QXHySpk8
	6dpPmm0UlCHETTpwl6iXhTwcWIc00A5SBGt6NUZBUUXdBT+WiRtxsejW78FzxQl2nbkEfy77kuhXx
	Dw9TBAnv49JMAVytR7WLf7Q+nRaocb9Y4lBlilv3vL/J1h02kjQx8LnY/fzLQIRNS5DY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: let unread watch events time out
Message-Id: <E1opr3l-0003k2-U3@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:12:05 +0000

commit 5285dcb1a5c01695c11e6397c95d906b5e765c98
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 133 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b9a0ff5e05..cce02f24b5 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -108,6 +108,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -207,19 +209,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -407,6 +482,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -427,10 +503,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (conn_can_read(conn) ||
 			    (conn_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -790,6 +868,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -841,6 +920,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -2185,6 +2270,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2207,6 +2295,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2220,6 +2309,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2234,7 +2356,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:U", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2284,6 +2406,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
@@ -2714,6 +2839,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 		barf("error restoring buffered data");
 
 	memcpy(bdata->buffer, data, len);
+	if (bdata->hdr.msg.type == XS_WATCH_EVENT && timeout_watch_event_msec &&
+	    domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index c9ea796185..745262af96 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -67,6 +68,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -118,6 +121,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -242,6 +246,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:12:17 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:12:17 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434612.686926 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3x-0000X7-9E; Tue, 01 Nov 2022 13:12:17 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434612.686926; Tue, 01 Nov 2022 13:12:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr3x-0000X0-6E; Tue, 01 Nov 2022 13:12:17 +0000
Received: by outflank-mailman (input) for mailman id 434612;
 Tue, 01 Nov 2022 13:12:16 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3w-0000Wj-2o
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:16 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3w-00072D-2D
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:16 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr3w-0003kT-1F
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:16 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=pbaSp0tHRsNAkmMEz2ImxM/PGxzk11GiT/GPd6cn6GY=; b=3nKYddagLlHe6iRO2kuMw9O2s9
	zJOqs8NTYlmSN0W/S9yzbPwBPA+yEWXwZkrWmMQ4Ht3BH9pUeC5hzjRNKSK45x4B+76Pj3GyB5YXY
	4YkgvZmHg+sUA3Xq3Qxi0I0YZRsRogda1il1rvwGe8TeP3O9WvGIslp9LyLm1duRrzMY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: limit outstanding requests
Message-Id: <E1opr3w-0003kT-1F@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:12:16 +0000

commit 36de433a273f55d614c83b89c9a8972287a1e475
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 88 +++++++++++++++++++++++++++++++++++++--
 tools/xenstore/xenstored_core.h   | 20 ++++++++-
 tools/xenstore/xenstored_domain.c | 38 ++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 +++++--
 5 files changed, 150 insertions(+), 14 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index cce02f24b5..54e6add1a1 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -107,6 +107,7 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -219,12 +220,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -240,6 +253,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -401,6 +438,7 @@ int delay_request(struct connection *conn, struct buffered_data *in,
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -414,6 +452,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -889,6 +932,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -896,7 +941,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -926,8 +972,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1714,6 +1765,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1787,6 +1839,7 @@ struct connection *new_connection(const struct interface_funcs *funcs)
 	new->is_stalled = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 	INIT_LIST_HEAD(&new->delayed);
@@ -2270,6 +2323,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2295,6 +2351,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2342,6 +2399,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2356,8 +2427,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
-				  NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
 			no_domain_init = true;
@@ -2406,6 +2477,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
@@ -2848,6 +2922,14 @@ static void add_buffered_data(struct buffered_data *bdata,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	/*
+	 * Watch events are never "outstanding", but the request causing them
+	 * are instead kept "outstanding" until all watch events caused by that
+	 * request have been delivered.
+	 */
+	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
+		domain_outstanding_inc(conn);
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 745262af96..acb6b9fe2a 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -56,6 +56,8 @@ struct xs_state_connection;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -63,6 +65,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -123,6 +136,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -191,7 +207,8 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -245,6 +262,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index de349e2a77..c0a37712f8 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -78,6 +78,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -183,8 +186,12 @@ static bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	return (intf->req_cons != intf->req_prod);
 }
@@ -331,7 +338,7 @@ static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -392,9 +399,6 @@ static int new_domain(struct domain *domain, int port, bool restore)
 	domain->conn->domain = domain;
 	domain->conn->id = domain->domid;
 
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
-
 	return 0;
 }
 
@@ -970,6 +974,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4a37de67a0..617d0acfd7 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,6 +65,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 205d9d8ea1..0755ffa375 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -269,8 +272,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	trace_create(watch, "watch");
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:12:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:12:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434613.686929 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr48-0000aj-CP; Tue, 01 Nov 2022 13:12:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434613.686929; Tue, 01 Nov 2022 13:12:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr48-0000aZ-9c; Tue, 01 Nov 2022 13:12:28 +0000
Received: by outflank-mailman (input) for mailman id 434613;
 Tue, 01 Nov 2022 13:12:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr46-0000aD-69
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr46-00072K-5S
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:26 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr46-0003ku-4b
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:26 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=1PvJgJqPZVikz0WY/tZnE+oiLjoAqalgqWSAv5v/f7E=; b=4lxwRoOi8IfBNorIyKvJDsdDJo
	PhFJxcEMe5KPzzQDMc4uE3e5s91jHNSCHODizC7iWAnm3FVsKSVo+Na9AkFwav20LbHnvYujGbG+b
	OFOL9d0WOFVjBYUUfHT7D3qyQGbLutHVtZ/z/Wcf4/LLrnoSgb3rUMLEnufEqrwy/IH0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1opr46-0003ku-4b@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:12:26 +0000

commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 54e6add1a1..45feae313a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -912,6 +912,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -944,7 +945,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -966,12 +967,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index acb6b9fe2a..e1d47f8844 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -62,6 +62,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:12:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:12:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434615.686934 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4H-0000db-Dj; Tue, 01 Nov 2022 13:12:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434615.686934; Tue, 01 Nov 2022 13:12:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4H-0000dS-B2; Tue, 01 Nov 2022 13:12:37 +0000
Received: by outflank-mailman (input) for mailman id 434615;
 Tue, 01 Nov 2022 13:12:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4G-0000dE-9A
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4G-00072j-8T
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4G-0003lP-7m
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0i07XmQGdnvTKoxDWcgkDjIjfFSpNk9AqTDmd/54Rik=; b=2R6QlP1DnDMtvdBd7a/oIEn8vQ
	+ToHXumBltW2fupl39+ajJaMGXCK+CkhMyt4dL8NZyrEwzY6sqK7UeKKHEIU2j2MPxffTp2L2wZ8P
	FibRPGHJVgY57XZtLVrtnDR64FrSKFnZ5RGKOjESAFIYU6BOMLrldWRZ0DEWvZvlgHX0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: fix connection->id usage
Message-Id: <E1opr4G-0003lP-7m@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:12:36 +0000

commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index f0e00db633..61bcbc069d 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -878,7 +878,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	unsigned int cmd, num, off;
 	char **vec = NULL;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	off = get_string(in, 0);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index e1d47f8844..aa0dedde64 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -123,7 +123,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this connection ignored? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 54432907fc..ee1b09031a 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -477,7 +477,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:12:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:12:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434616.686938 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4R-0000gG-Fb; Tue, 01 Nov 2022 13:12:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434616.686938; Tue, 01 Nov 2022 13:12:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4R-0000g8-CX; Tue, 01 Nov 2022 13:12:47 +0000
Received: by outflank-mailman (input) for mailman id 434616;
 Tue, 01 Nov 2022 13:12:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4Q-0000fy-CX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4Q-00072n-Bo
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4Q-0003m7-Ay
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=vOEJp3O2zZB4N5kLqhwVNxrxH65wqE8dBjwakLkWvVU=; b=lSAraHX0H9e1CJR78wkWbvOnk3
	XMWBimKamb5VkX1fbS12YZNhA6Iz2i7IhStwSPNnM4RCJTmV/URvknWGhcc5OMUMP5rdV16wd+ong
	I6JSe2b4n2Y0Wh3HbwK4zgukyJcvW4oxeaJFPDhV/FMRvc+FJEj/36eTlbzw8o2X7s8M=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1opr4Q-0003m7-Ay@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:12:46 +0000

commit dbef1f7482894c572d90cd73d99ed689c891e863
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c        |  43 +++++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 4 files changed, 109 insertions(+), 51 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 45feae313a..0a684450bc 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -634,7 +634,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -656,7 +656,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1268,13 +1268,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1324,8 +1328,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1610,10 +1618,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
+
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
 
-	if (write_node(conn, node, false))
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
@@ -3095,7 +3120,9 @@ void read_state_node(const void *ctx, const void *state)
 	set_tdb_key(name, &key);
 	if (write_node_raw(NULL, &key, node, true))
 		barf("write node error restoring node");
-	domain_entry_inc(&conn, node);
+
+	if (domain_entry_inc(&conn, node))
+		barf("node accounting error restoring node");
 
 	talloc_free(node);
 }
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index c0a37712f8..44ce267ec5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -363,6 +364,18 @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid)
 	return domain ? : alloc_domain(ctx, domid);
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port, bool restore)
 {
 	int rc;
@@ -814,30 +827,28 @@ void domain_deinit(void)
 		xenevtchn_unbind(xce_handle, virq_port);
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -873,7 +884,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -883,8 +894,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -903,25 +920,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -931,13 +948,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 617d0acfd7..5937931314 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -55,10 +55,10 @@ const char *get_implicit_path(const struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ee1b09031a..86caf6c398 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -519,8 +519,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:12:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:12:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434617.686942 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4b-0000jJ-HN; Tue, 01 Nov 2022 13:12:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434617.686942; Tue, 01 Nov 2022 13:12:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4b-0000jB-E7; Tue, 01 Nov 2022 13:12:57 +0000
Received: by outflank-mailman (input) for mailman id 434617;
 Tue, 01 Nov 2022 13:12:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4a-0000j3-Fz
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4a-00072y-FG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4a-0003mj-EO
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:12:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=HKKV+rS2lEgZKK8t9AGBruVLJq5PTrHpBmeP8NHb0FQ=; b=rI7gmCZDQjfUntmMZz0cJK7U+b
	tPqVpK9plkLA6qx7WSIEX2SpGTIPqkhm7mMN8cUlywX0BAb1xmz6G4nRFNB4z4o80/oVRcTDQjZ8/
	X5OOMQV+NEM+uxvKqyGqWlf9k/asO4yIGgTaDFmN7817U1k0/Kz3jmQ9Q59ogOEtfvG0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1opr4a-0003mj-EO@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:12:56 +0000

commit 268369d8e322d227a74a899009c5748d7b0ea142
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  1 +
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index a16e0c3807..bafc90e2f6 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -63,4 +63,8 @@
 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 0a684450bc..d4fd005f59 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -106,6 +106,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
 
@@ -591,6 +592,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -612,14 +614,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -634,19 +635,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -763,7 +781,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -825,7 +843,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1231,7 +1249,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1505,7 +1523,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1535,7 +1553,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2368,6 +2386,8 @@ static void usage(void)
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2452,6 +2472,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index aa0dedde64..9c572a3c6e 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -266,6 +266,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 86caf6c398..7bd41eb475 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -260,6 +263,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -297,6 +305,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:13:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:13:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434618.686947 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4l-0000mP-K5; Tue, 01 Nov 2022 13:13:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434618.686947; Tue, 01 Nov 2022 13:13:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4l-0000mH-HC; Tue, 01 Nov 2022 13:13:07 +0000
Received: by outflank-mailman (input) for mailman id 434618;
 Tue, 01 Nov 2022 13:13:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4k-0000m6-Je
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:06 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4k-00073F-Ix
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:06 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4k-0003oF-I2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=3wJ2wSJgd9/feDqENQ7hsEEM1FWorM59ELKwoMT5Us8=; b=JHJQnSgmKjEne+tSGvsGFBDcpE
	60eptwTtL8+UDzGZoleSzSUVOqCm1P4Uhqm/h5/DQ6hgCVbZQ3K/nDJPrld7DjZFSB8Rl035BO3Jf
	af/Gr955U3cS+5+cI0BB2sx1XX38HetO6Ytxjkw5LyhfP/vwE9EkY68yUErO/3hqt9qs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1opr4k-0003oF-I2@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:13:06 +0000

commit 60e2f6020dea7f616857b8fc1141b1c085d88761
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 3 +++
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index d4fd005f59..844ae396a0 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2018,7 +2018,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -2057,7 +2058,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(bool live_update)
+void setup_structure(bool live_update)
 {
 	char *tdbname;
 
@@ -2080,6 +2081,7 @@ static void setup_structure(bool live_update)
 		manual_node("/", "tool");
 		manual_node("/tool", "xenstored");
 		manual_node("/tool/xenstored", NULL);
+		domain_entry_fix(dom0_domid, 3, true);
 	}
 
 	check_store();
@@ -2598,9 +2600,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure(live_update);
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init && !live_update) {
 		domain_init(-1);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 9c572a3c6e..a772f3b8ea 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -231,6 +231,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(bool live_update);
 struct connection *new_connection(const struct interface_funcs *funcs);
 struct connection *get_connection_by_id(unsigned int conn_id);
 void check_store(void);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 44ce267ec5..5c79eed3dc 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -496,6 +496,9 @@ static struct domain *introduce_domain(const void *ctx,
 		}
 		domain->interface = interface;
 
+		if (is_master_domain)
+			setup_structure(restore);
+
 		/* Now domain belongs to its connection. */
 		talloc_steal(domain->conn, domain);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:13:17 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:13:17 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434619.686951 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4v-0000pI-Lw; Tue, 01 Nov 2022 13:13:17 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434619.686951; Tue, 01 Nov 2022 13:13:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr4v-0000pA-Ig; Tue, 01 Nov 2022 13:13:17 +0000
Received: by outflank-mailman (input) for mailman id 434619;
 Tue, 01 Nov 2022 13:13:16 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4u-0000ow-Mf
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:16 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4u-00073K-M3
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:16 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr4u-0003os-LR
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:16 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=bsoKzao8vuVfg+aZVIPXE5AJeBJ+mLVNnoA3SBrSnjU=; b=ALM8eURbhXLaGA3ZJTl4IkLR5n
	4SDqPrees1uZe3iysURqHqunSVVprlaX5THiZ0MLki1REYwTj4JoXOeYrDClJt2gGTsgNSRl8yRwy
	qlxcbPOo1qpHh+dxnNBCfTZ6mA8+MF5ZzElgeaxunJMBwb8s+7moL9hixqiw4G0W9CiA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1opr4u-0003os-LR@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:13:16 +0000

commit 0d4a8ec7a93faedbe54fd197db146de628459e77
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 844ae396a0..f03ad93b43 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -109,6 +109,8 @@ int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2390,7 +2392,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2417,6 +2426,7 @@ static struct option options[] = {
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2464,7 +2474,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2472,11 +2482,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2494,7 +2509,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2545,7 +2560,10 @@ int main(int argc, char *argv[])
 						 quota_max_path_len);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index a772f3b8ea..ec52d8d3ff 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -268,6 +268,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 5c79eed3dc..4242380886 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -76,6 +76,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -192,6 +199,9 @@ static bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	return (intf->req_cons != intf->req_prod);
@@ -982,6 +992,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5937931314..d342e5e867 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -62,6 +62,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:13:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:13:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434621.686954 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr55-0000sN-Mv; Tue, 01 Nov 2022 13:13:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434621.686954; Tue, 01 Nov 2022 13:13:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr55-0000sF-KJ; Tue, 01 Nov 2022 13:13:27 +0000
Received: by outflank-mailman (input) for mailman id 434621;
 Tue, 01 Nov 2022 13:13:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr54-0000s3-Ps
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr54-00073Y-PL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:26 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr54-0003qK-Ob
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:26 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=cYaps0TdftIzZHsJlUpt/cz65V4fJ6uE9nxQyQOad0A=; b=3syq0ASYzEHmUmX2ojMsxC09w6
	rnPGmfRq2jyMPdmJ8CwUQwLbLG+EEGwklkboYXgEFjbuDl3g33SSzaXjVzMG4qhln3UQGD1lE/NzL
	etfTLUuZUG9Sj0TzPb641cT68vCJV6cd9roDxqhcyYYoXPyuNQbYBgaMMOeRESizfJFY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: add memory accounting for responses
Message-Id: <E1opr54-0003qK-Ob@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:13:26 +0000

commit f6d00133643a524d2138c9e3f192bbde719050ba
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    This is part of XSA-326 / CVE-2022-42315.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f03ad93b43..009eaa8e5f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -256,6 +256,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -934,11 +936,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -1003,6 +1008,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
@@ -3012,6 +3022,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 	 */
 	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
 		domain_outstanding_inc(conn);
+	/*
+	 * We are restoring the state after Live-Update and the new quota may
+	 * be smaller. So ignore it. The limit will be applied for any resource
+	 * after the state has been fully restored.
+	 */
+	domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:13:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:13:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434622.686958 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5F-0000vU-Oo; Tue, 01 Nov 2022 13:13:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434622.686958; Tue, 01 Nov 2022 13:13:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5F-0000vI-Lp; Tue, 01 Nov 2022 13:13:37 +0000
Received: by outflank-mailman (input) for mailman id 434622;
 Tue, 01 Nov 2022 13:13:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5E-0000v3-St
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5E-00074K-SI
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5E-0003r5-Rf
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9lWG03x+0uw4MP5Ro7z44yTdbf9Eu8wZyMXHVW66pGg=; b=yQ3vjfXpRdPW1RAYi/EexlxyWq
	QO8Mcc0ARdaaWIPBTuwkdZBvihEBe2yMNtlAziLVHXJVNZkVYyTcXp2iPdQlmOgxJ9u+GaR18Km8s
	cm0ROWn2518wLl3jfST6pAAx1Ra3DVxVuzU0wS+Dx2SR30hIFkxYRjx/lQZ/+vx+3GKE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: add memory accounting for watches
Message-Id: <E1opr5E-0003r5-Rf@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:13:36 +0000

commit 7f9978a2cc37aaffab2fb09593bc598c0712a69b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    This is part of XSA-326 / CVE-2022-42315.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c  |  1 +
 tools/xenstore/xenstored_watch.c | 13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 009eaa8e5f..1a5ba4aba8 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -459,6 +459,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 0755ffa375..fdf9b2d653 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -211,7 +211,7 @@ static int check_watch_path(struct connection *conn, const void *ctx,
 }
 
 static struct watch *add_watch(struct connection *conn, char *path, char *token,
-			       bool relative)
+			       bool relative, bool no_quota_check)
 {
 	struct watch *watch;
 
@@ -222,6 +222,9 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	watch->token = talloc_strdup(watch, token);
 	if (!watch->node || !watch->token)
 		goto nomem;
+	if (domain_memory_add(conn->id, strlen(path) + strlen(token),
+			      no_quota_check))
+		goto nomem;
 
 	if (relative)
 		watch->relative_path = get_implicit_path(conn);
@@ -265,7 +268,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (domain_watch(conn) > quota_nb_watch_per_domain)
 		return E2BIG;
 
-	watch = add_watch(conn, vec[0], vec[1], relative);
+	watch = add_watch(conn, vec[0], vec[1], relative, false);
 	if (!watch)
 		return errno;
 
@@ -296,6 +299,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -311,6 +316,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
@@ -373,7 +380,7 @@ void read_state_watch(const void *ctx, const void *state)
 	if (!path)
 		barf("allocation error for read watch");
 
-	if (!add_watch(conn, path, token, relative))
+	if (!add_watch(conn, path, token, relative, true))
 		barf("error adding watch");
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:13:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:13:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434623.686962 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5P-0000xy-QE; Tue, 01 Nov 2022 13:13:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434623.686962; Tue, 01 Nov 2022 13:13:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5P-0000xq-NN; Tue, 01 Nov 2022 13:13:47 +0000
Received: by outflank-mailman (input) for mailman id 434623;
 Tue, 01 Nov 2022 13:13:47 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5P-0000xh-0X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:47 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5O-00074a-W2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5O-0003ri-Un
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=J0IQv6GdsoVFTm5ryx6X7VPF1a5I7rAUoN9OZH85YCg=; b=nATtpVhBxRErUtm44/i2YHLjB8
	MlXZmcZY893M4D1JkTxKEW2tEmJpbBsF2Znhu75400BpveDkMfMmsLsZsDgDqpPHGav4jKeeb+SuI
	JW/VNq2LepojvidMLe5+Hhy5em44ouqjqg4Is2VzeTnmWmF1egg8O8UC5k0uORmwyO80=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: add memory accounting for nodes
Message-Id: <E1opr5O-0003ri-Un@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:13:46 +0000

commit 00e9e32d022be1afc144b75acdaeba8393e63315
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    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>
---
 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 1a5ba4aba8..f7f1e00c71 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -587,6 +587,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.
@@ -640,9 +751,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. */
@@ -711,12 +828,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;
 }
 
@@ -1218,7 +1332,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;
 	}
@@ -1291,6 +1405,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;
 
@@ -1299,17 +1414,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);
 
 	/*
@@ -1361,7 +1476,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;
 			}
 		}
@@ -2270,7 +2385,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);
 		}
 	}
 
@@ -3122,6 +3237,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 ec52d8d3ff..031a821358 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -176,6 +176,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 */
@@ -198,6 +203,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. */
@@ -301,6 +309,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 7bd41eb475..ace9a11d77 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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:13:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:13:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434624.686967 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5Z-00011i-To; Tue, 01 Nov 2022 13:13:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434624.686967; Tue, 01 Nov 2022 13:13:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5Z-00011a-QX; Tue, 01 Nov 2022 13:13:57 +0000
Received: by outflank-mailman (input) for mailman id 434624;
 Tue, 01 Nov 2022 13:13:57 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5Z-00011N-3R
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:57 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5Z-00074k-2r
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:57 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5Z-0003tk-2A
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:13:57 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=4Jsg/mJjXHRkF8Wp/wQUemk3B92BGPyp0DI3sBoewEQ=; b=hnlrFlJBX2trCkMrCXD8eiCD8b
	Tow4nRT1W2p6ljDz3V3Dgxd9IAlbaKN646c9itZBrxD2d3+l3DwSHHF3q/OeqGM/opiMRb6oSFJO1
	0Ke0ziBjWan+dkmqCcKhuDRXfxp8y0B6772331QiTpT8Gqt/wwQ0H1fRjvK+scs/6lVA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: add exports for quota variables
Message-Id: <E1opr5Z-0003tk-2A@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:13:57 +0000

commit 1da16d5990b5f7752657fca3e948f735177ea9ad
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 031a821358..f7c37fe3b5 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -273,6 +273,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ace9a11d77..28774813de 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static struct accessed_node *find_accessed_node(struct transaction *trans,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index fdf9b2d653..85362bcce3 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:14:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:14:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434625.686972 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5j-00014F-WD; Tue, 01 Nov 2022 13:14:08 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434625.686972; Tue, 01 Nov 2022 13:14:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5j-000147-S7; Tue, 01 Nov 2022 13:14:07 +0000
Received: by outflank-mailman (input) for mailman id 434625;
 Tue, 01 Nov 2022 13:14:07 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5j-00013z-6W
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:07 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5j-000759-5w
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:07 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5j-0003um-5B
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:07 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=fNY8uqdv54Z5iiuDklazAixlKOm1vLwu9HvV4B+qPsc=; b=DX9gBL9LKgRWdFzgSQKCsO1sWq
	JzSDehU1ot9kjtEArd9xDESHhX5TPLdez4zmWGOTqvV85R2YC3dikO1Za833abyBO1w1LcHt3o7J/
	C95a/ytRMRfvmJ/8GPWuCQ7bCO5c7jfpzfQj9vHkLxKc/xDrm+6YbXymwtiyTKCrQLN8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1opr5j-0003um-5B@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:14:07 +0000

commit 9c484bef83496b683b0087e3bd2a560da4aa37af
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 4bc262fd5d..988ef89cba 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -410,6 +410,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 61bcbc069d..264bb39d7b 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -196,6 +196,115 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "path-max", &quota_max_path_len, "Max. length of a node path" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 #ifdef __MINIOS__
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
@@ -847,6 +956,8 @@ static struct cmd_s cmds[] = {
 	{ "memreport", do_control_memreport, "[<file>]" },
 #endif
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 4242380886..983b348ee5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -345,6 +346,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index d342e5e867..5b86a92e1b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -88,6 +88,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:14:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:14:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434626.686974 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5u-00016u-01; Tue, 01 Nov 2022 13:14:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434626.686974; Tue, 01 Nov 2022 13:14:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr5t-00016n-Tq; Tue, 01 Nov 2022 13:14:17 +0000
Received: by outflank-mailman (input) for mailman id 434626;
 Tue, 01 Nov 2022 13:14:17 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5t-00016b-9X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:17 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5t-00075J-8t
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:17 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr5t-0003vL-8A
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:17 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Z6r5ZstAKo07W6I8I7eM7hxhJD743psKb8g8jStnpGI=; b=gZg1x47t+i33Z1QYvcRilTb1dB
	TgOrNo6AdkHAElF/L8j6LdDAMapqNJqjPdkph1p4Ln/ov8FQwpndzGDqepqjgUv3ghpCWYISfmnUz
	Xf4LwUw7AzvoORbCaNZSG4i0ep44aB7DgaKsdc21HbXNJRcnxWBG7uSQz2V29+wBUQY0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1opr5t-0003vL-8A@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:14:17 +0000

commit 84734955d4bf629ba459a74773afcde50a52236f
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ebe18b8e31..6b06f80859 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -21,9 +21,9 @@ let xs_daemon_socket = Paths.xen_run_stored ^ "/socket"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:14:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:14:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434627.686978 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr64-00019b-2C; Tue, 01 Nov 2022 13:14:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434627.686978; Tue, 01 Nov 2022 13:14:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr63-00019T-VP; Tue, 01 Nov 2022 13:14:27 +0000
Received: by outflank-mailman (input) for mailman id 434627;
 Tue, 01 Nov 2022 13:14:27 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr63-00019M-CL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:27 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr63-00075V-Bi
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:27 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr63-0003vv-B6
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:27 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=dFvtmPeNfdE/yt7iDAJEU0bzFrYb+984AwIFgrAQjmc=; b=jsFpg4BuiOKPfJzHIoyVm3Y/73
	KGYuv1EL2/YmFhhMaKXn5arwe2tn2s6sOhQTptPNPmvpwFoR+2SaVW9WjMdC4hdyUzzXpjPuko2Gs
	Sh6F/pias+rWlNSq76Zl48GmrV0Vk8dRWOvjjEEHfbFt1OdDZo/XwAK6gcusLwN4eYDo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1opr63-0003vv-B6@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:14:27 +0000

commit 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    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>
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 86eed02413..d0400419ab 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -389,6 +389,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"
@@ -682,9 +683,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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:14:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:14:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434628.686982 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6F-0001DB-3Z; Tue, 01 Nov 2022 13:14:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434628.686982; Tue, 01 Nov 2022 13:14:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6F-0001D3-0s; Tue, 01 Nov 2022 13:14:39 +0000
Received: by outflank-mailman (input) for mailman id 434628;
 Tue, 01 Nov 2022 13:14:37 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6D-0001Cs-FC
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:37 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6D-00075v-Ec
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:37 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6D-0003wL-Dx
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:37 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=gagtPI0RyQWcJysV25+h3xU4S8qzf8llssvtxgf2fa8=; b=q8mrKZvDB4eKRCIqQtYIGvjoLt
	nBTWI9gAC3ivS6hRhXo7KSgWTyDonh96CiSus8jdHVVBGlaqBOcvMCxdJgztAqCkUhaQtSViGwdFt
	dG8ibaGGZPFL+JG53LGZ/0vBKPRoiDgQX3tH3BazSeex8y43uPE+jDrt5ut78pQauksc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/ocaml: GC parameter tuning
Message-Id: <E1opr6D-0003wL-Dx@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:14:37 +0000

commit 4a8bacff20b857ca0d628ef5525877ade11f2a42
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 6b06f80859..ba63a8147e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index acc7290627..3a932f54a6 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -104,6 +104,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -265,6 +266,67 @@ let to_file store cons fds file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -274,6 +336,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:14:49 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:14:49 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434629.686985 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6P-0001GC-6S; Tue, 01 Nov 2022 13:14:49 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434629.686985; Tue, 01 Nov 2022 13:14:49 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6P-0001G2-3k; Tue, 01 Nov 2022 13:14:49 +0000
Received: by outflank-mailman (input) for mailman id 434629;
 Tue, 01 Nov 2022 13:14:47 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6N-0001Fp-ID
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:47 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6N-000765-HY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:47 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6N-0003wm-Gu
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:47 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=h+xEAK4xpFmqTUKF+lxv5AyRH9/IlywN0KZz3VXay3s=; b=ohBbMnv2g8H+5f2kRYQpSaByvY
	i1B6bxHGomXvSCYs9/OYOXdO3HPQPTuuyznOOQq4lWuxM89IGHcpEwU2XpYFc1YM2YdXjbzqzSHxa
	CXi+qMpnPUy5wW0PMVf5D1MWXaHBAbhhVvnHySCtUtJ2u4tSTmfvsYz3Uc7cSlqonEQM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1opr6N-0003wm-Gu@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:14:47 +0000

commit c0a86a462721008eca5ff733660de094d3c34bc7
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  4 +---
 tools/ocaml/xenstored/process.ml    | 15 +++++++--------
 5 files changed, 20 insertions(+), 42 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 64180bb2d5..3f6a8f1ad0 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,9 +277,7 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
@@ -307,7 +305,7 @@ let is_bad con = match con.dom with None -> false | Some dom -> Domain.is_bad_do
    Restrictions below can be relaxed once xenstored learns to dump more
    of its live state in a safe way *)
 let has_extra_connection_data con =
-	let has_in = has_input con || has_partial_input con in
+	let has_in = has_partial_input con in
 	let has_out = has_output con in
 	let has_nondefault_perms = make_perm con.dom <> con.perm in
 	has_in || has_out
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index d0400419ab..50ef05be41 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -195,10 +195,9 @@ let parse_live_update args =
 			| _ when Unix.gettimeofday () < t.deadline -> false
 			| l ->
 				warn "timeout reached: have to wait, migrate or shutdown %d domains:" (List.length l);
-				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, in: %b, out: %b, perm: %s"
+				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, out: %b, perm: %s"
 					(Connection.get_domstr con)
 					(Connection.number_of_transactions con)
-					(Connection.has_input con)
 					(Connection.has_output con)
 					(Connection.get_perm con |> Perms.Connection.to_string)
 					) l in
@@ -707,16 +706,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -726,8 +726,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:14:59 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:14:59 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434630.686991 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6Z-0001J2-8U; Tue, 01 Nov 2022 13:14:59 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434630.686991; Tue, 01 Nov 2022 13:14:59 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6Z-0001Is-5C; Tue, 01 Nov 2022 13:14:59 +0000
Received: by outflank-mailman (input) for mailman id 434630;
 Tue, 01 Nov 2022 13:14:57 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6X-0001If-Ks
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:57 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6X-000769-KI
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:57 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6X-0003xe-Jk
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:14:57 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=u/d5vR/eVCJ9e4Yr9Y0yYTr/DSxh09jDnQZu7U1cZvs=; b=t6HAxNLKKImJhEQstt+kmbxNRf
	R1HMjAuDZeEueMT+BV2DqmJpCa2NNtrSiLuFO8dSgCDRTppC2VEwWX4knHOWoYGbavJF/nACPsZPI
	SrbPo25ttSGkh3A8mcUPdoDjygSWdK1dEJBcgUMcM8D/NNu0Rz0litgNff7p1Fqn/jP0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1opr6X-0003xe-Jk@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:14:57 +0000

commit 19171fb5d888b4467a7073e8febc5e05540956e9
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:15:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:15:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434631.686994 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6j-0001Ly-9r; Tue, 01 Nov 2022 13:15:09 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434631.686994; Tue, 01 Nov 2022 13:15:09 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6j-0001Lq-6u; Tue, 01 Nov 2022 13:15:09 +0000
Received: by outflank-mailman (input) for mailman id 434631;
 Tue, 01 Nov 2022 13:15:07 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6h-0001LY-O5
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:07 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6h-00076d-NO
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:07 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6h-0003yX-Mo
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:07 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=3uaWvKIEoVLhUiN012/BIL+3OMFZObf9HW5ZBgTnmUM=; b=MK7zaNfsozmOulqnHGcSzeDxCD
	Ges/q8LrDjSeKU/+OJBlJQMIDWdWMUt+3K4dszaqMfDojUccOtXk7I6Ok26jPSINqCRthhkDZzxiP
	bgg1TPS2Pbd5teMkk9EWr5wi6C4Y0jpWJVGhnkGSiVE0rZu0rpYIoS7xdQ53lbmLeRyM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1opr6h-0003yX-Mo@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:15:07 +0000

commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 3f6a8f1ad0..54f7f76516 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -280,6 +408,7 @@ let do_input con = Xenbus.Xb.input con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -322,7 +451,7 @@ let prevents_live_update con = not (is_bad con)
 	&& (has_extra_connection_data con || has_transaction_data con)
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 3c7429fe7f..7d68c583b4 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: Connection.watch list Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -197,6 +216,16 @@ let debug cons =
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
 
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
+
 let filter ~f cons =
 	let fold _ v acc = if f v then v :: acc else acc in
 	[]
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ba63a8147e..327b6d795e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -24,6 +24,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 50ef05be41..6781088387 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -57,7 +57,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.Transaction.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -67,8 +67,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -234,6 +235,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -342,7 +357,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -501,7 +516,7 @@ let do_watch con _t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -532,7 +547,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -701,7 +716,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -729,6 +745,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 3a932f54a6..ffd43a4eee 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:15:19 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:15:19 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434632.686998 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6t-0001Px-Dl; Tue, 01 Nov 2022 13:15:19 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434632.686998; Tue, 01 Nov 2022 13:15:19 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr6t-0001Pr-AR; Tue, 01 Nov 2022 13:15:19 +0000
Received: by outflank-mailman (input) for mailman id 434632;
 Tue, 01 Nov 2022 13:15:17 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6r-0001Pd-Qu
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:17 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6r-00076s-QI
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:17 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr6r-0003zE-Pj
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:17 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=PtN8oTP4ajQuVm4ga6QvzLV/o3JgvoYZw7yplN/rde0=; b=gx1SdFLwBwLM+DFClNCXe+OKJz
	1KsDm4zjfOY8ujQkTdgKyQFyp6eCcwGLUXkidbfKsfYClD3KZ4o0gPalkrB0MbQB33vSObMgeANZn
	OplzmncH0bmJbF5BoMg7IRcB3feFMyJmFQ2qRaQwC3znW0ZuTFwVz+jBfqW+hqRNIa3E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1opr6r-0003zE-Pj@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:15:17 +0000

commit c7bc20d8d123851a468402bbfc9e3330efff21ec
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
---
 SUPPORT.md | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index cf2ddfacaf..ab71464cf6 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -193,13 +193,18 @@ Support for running qemu-xen device model in a linux stubdomain.
 
     Status: Tech Preview
 
-## Liveupdate of C xenstored daemon
+## Xenstore
 
-    Status: Tech Preview
+### C xenstored daemon
 
-## Liveupdate of OCaml xenstored daemon
+    Status: Supported
+    Status, Liveupdate: Tech Preview
 
-    Status: Tech Preview
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+    Status, Liveupdate: Not functional
 
 ## Toolstack/3rd party
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:15:29 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:15:29 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434633.687002 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr73-0001Sw-Ev; Tue, 01 Nov 2022 13:15:29 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434633.687002; Tue, 01 Nov 2022 13:15:29 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr73-0001So-C2; Tue, 01 Nov 2022 13:15:29 +0000
Received: by outflank-mailman (input) for mailman id 434633;
 Tue, 01 Nov 2022 13:15:27 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr71-0001Sd-U4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:27 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr71-00077C-TS
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:27 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr71-00040p-Sn
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:27 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=vPC6Pzc0i4JTRnlQ5iC9K4gpJYGvTy9bWylXleMWiN0=; b=WLSF8QSAR4f61pDVfrCQyoaMdX
	cNmBzjpTOZ1HIcpIYKbfo4ZW+j7U33/xepQAFXjAdH7BSjZu/rXsGCBm1WSwGRcsRauRYf460X29G
	RA5kRoaWiUFMuF3EyQ21nbQmPFc0sk85fJdTxuSQ/HQWjYQtu/NN1y66xkku2Gz3wn0Y=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1opr71-00040p-Sn@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:15:27 +0000

commit 2a587de219cc0765330fbf9fac6827bfaf29e29b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_control.c     | 31 +++++++-------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 29 +++++++------
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 118 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 264bb39d7b..d1aaa00bf4 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -155,7 +155,7 @@ bool lu_is_pending(void)
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 	/*
 	 * max_pars can be used to limit the size of the parameter vector,
@@ -167,7 +167,7 @@ struct cmd_s {
 	unsigned int max_pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -179,7 +179,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -281,7 +281,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -293,7 +293,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -306,7 +306,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 }
 
 #ifdef __MINIOS__
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	if (num)
@@ -318,7 +318,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 #else
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -333,7 +333,7 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -373,7 +373,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -875,7 +875,7 @@ static const char *lu_start(const void *ctx, struct connection *conn,
 	return NULL;
 }
 
-static int do_control_lu(void *ctx, struct connection *conn,
+static int do_control_lu(const void *ctx, struct connection *conn,
 			 char **vec, int num)
 {
 	const char *ret = NULL;
@@ -922,7 +922,7 @@ static int do_control_lu(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -961,7 +961,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd;
@@ -984,7 +984,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	unsigned int cmd, num, off;
 	char **vec = NULL;
@@ -1004,11 +1005,11 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (cmds[cmd].max_pars)
 		num = min(num, cmds[cmd].max_pars);
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) < num)
 		return EIO;
 
-	return cmds[cmd].func(in, conn, vec + 1, num - 1);
+	return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index 98b6fbcea2..a8cb76559b 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,7 +16,8 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 void lu_read_state(void);
 
 struct connection *lu_get_connection(void);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f7f1e00c71..66bbeaf6bf 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1244,11 +1244,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1257,7 +1259,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1269,7 +1271,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1296,7 +1299,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1312,11 +1315,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1506,7 +1511,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1520,12 +1526,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1536,18 +1542,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1557,10 +1564,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 			return errno;
 		if (!name)
 			return ENOMEM;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1658,24 +1665,25 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
 			if (!name)
 				return ENOMEM;
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1690,7 +1698,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1700,13 +1708,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1719,7 +1729,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1736,7 +1747,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1751,7 +1762,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1786,7 +1797,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1794,7 +1805,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1847,6 +1859,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	/* At least send_error() and send_reply() expects conn->in == in */
 	assert(conn->in == in);
@@ -1871,10 +1884,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 983b348ee5..b9ff4ded83 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -330,7 +330,7 @@ bool domain_is_unprivileged(struct connection *conn)
 	       domid_is_unprivileged(conn->domain->domid);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -566,7 +566,8 @@ static struct domain *introduce_domain(const void *ctx,
 }
 
 /* domid, gfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -584,7 +585,7 @@ int do_introduce(struct connection *conn, struct buffered_data *in)
 	if (port <= 0)
 		return EINVAL;
 
-	domain = introduce_domain(in, domid, port, false);
+	domain = introduce_domain(ctx, domid, port, false);
 	if (!domain)
 		return errno;
 
@@ -607,7 +608,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -651,7 +653,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -666,7 +669,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -681,7 +685,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -689,18 +694,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -721,7 +725,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5b86a92e1b..2094421909 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -24,25 +24,32 @@ void handle_event(void);
 void check_domains(void);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(int evtfd);
 void dom0_init(void);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 28774813de..3e3eb47326 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -481,7 +481,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -494,8 +495,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -544,7 +545,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -562,8 +564,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	if (!conn->transaction_started)
 		conn->ta_start_time = 0;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 85362bcce3..316c08b7f7 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -243,7 +243,7 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	return NULL;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -252,7 +252,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	errno = check_watch_path(conn, in, &(vec[0]), &relative);
+	errno = check_watch_path(conn, ctx, &(vec[0]), &relative);
 	if (errno)
 		return errno;
 
@@ -283,7 +283,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -291,7 +292,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 0e693f0839..091890edca 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:15:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:15:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434634.687006 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7D-0001W0-Hw; Tue, 01 Nov 2022 13:15:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434634.687006; Tue, 01 Nov 2022 13:15:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7D-0001Vs-F1; Tue, 01 Nov 2022 13:15:39 +0000
Received: by outflank-mailman (input) for mailman id 434634;
 Tue, 01 Nov 2022 13:15:38 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7C-0001Vi-1B
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:38 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7C-00077f-0T
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:38 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7B-000454-Vo
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:37 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=RVV1eVJZWtBdl/BjsfXMX7I2dF4tOl37+HIkkKzxVBU=; b=gZwEeiWoyWno1MBl8Qx3wq2tmV
	F43JYYgDjgUok4/qTpQ0mCCRyqPax3oDstPaUZIRpE65Hmbd2YtUOYAu9OHxaK2oWTXuQBvP55gdB
	xHCEP5vrqJiEdxa7/U5oBqXyfpBWOQrMZ+ErkOTqQLde5FU55nEF0Y/wpZbeeR0nL9KA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: fix checking node permissions
Message-Id: <E1opr7B-000454-Vo@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:15:37 +0000

commit ab128218225d3542596ca3a02aee80d55494bef8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 66bbeaf6bf..a0c176fa20 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1753,6 +1753,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index b9ff4ded83..98b401fdec 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -907,7 +907,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -915,20 +914,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -941,8 +958,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -959,8 +974,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 2094421909..7fe0a21d9e 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -63,6 +63,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:15:49 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:15:49 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434635.687012 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7N-0001Yg-Jq; Tue, 01 Nov 2022 13:15:49 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434635.687012; Tue, 01 Nov 2022 13:15:49 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7N-0001YX-Ge; Tue, 01 Nov 2022 13:15:49 +0000
Received: by outflank-mailman (input) for mailman id 434635;
 Tue, 01 Nov 2022 13:15:48 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7M-0001YD-3z
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:48 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7M-00077r-3O
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:48 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7M-00045h-2q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:48 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=/vzWxoty/o9HvnBA4e+fJncBGNWH6597v1/N/lYfGnE=; b=y09flvn3z065ng6LfuZFl/Au8N
	v08VXSTicrHkGrFNOC/uUQriE8XQ/dxaV+5ItU6WK7QhAas3d4v0efeanXyuB0Lf9ShCCGZ2WbWV8
	n69h20RF17DAGezYOeRAJtUjeARljp+htSX3c+ZbctVO94MXEZ8pGpulMAJICYOJoahQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1opr7M-00045h-2q@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:15:48 +0000

commit da8ee25d02a5447ba39a9800ee2a710ae1f54222
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 86 ++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 31 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index a0c176fa20..cb52f68d4d 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1373,45 +1373,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name)
 static struct node *construct_node(struct connection *conn, const void *ctx,
 				   const char *name)
 {
-	struct node *parent, *node;
-	char *parentname = get_parent(ctx, name);
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
 
 	if (!parentname)
 		return NULL;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
 
-	/* Add child to parent. */
-	if (add_child(ctx, parent, name))
-		goto nomem;
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
 
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
 
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:15:59 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:15:59 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434636.687016 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7X-0001c2-N1; Tue, 01 Nov 2022 13:15:59 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434636.687016; Tue, 01 Nov 2022 13:15:59 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7X-0001bu-IN; Tue, 01 Nov 2022 13:15:59 +0000
Received: by outflank-mailman (input) for mailman id 434636;
 Tue, 01 Nov 2022 13:15:58 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7W-0001ba-6y
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:58 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7W-00078E-6K
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:58 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7W-00046s-5g
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:15:58 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=fgvF633XkHmFb9TuL7e7NKSR6uW6vOcHckbVwLqym4M=; b=58gzFqFFJLSjotV5o7PcmN1ei5
	Ie0/ic76Dk0IM0B7TumVaiq1nM/aClrSwiaCI5LaJY1Jjt5wnXuOSRHPqlC5+QEBtnxZaUuNBuZfT
	LcqevopTphTyl1bcHlqoR9VPpLpAxcsUt5i/W6KAk62js8VG/B3q+wzGJ6uWLbu7k/dM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1opr7W-00046s-5g@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:15:58 +0000

commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index cb52f68d4d..5642917e67 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1604,15 +1604,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1622,7 +1622,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2304,6 +2306,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2356,12 +2369,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2378,11 +2386,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:16:11 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:16:11 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434637.687018 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7h-0001eq-Mk; Tue, 01 Nov 2022 13:16:09 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434637.687018; Tue, 01 Nov 2022 13:16:09 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7h-0001eg-Jy; Tue, 01 Nov 2022 13:16:09 +0000
Received: by outflank-mailman (input) for mailman id 434637;
 Tue, 01 Nov 2022 13:16:08 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7g-0001eU-BZ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:08 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7g-00078X-9D
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:08 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7g-00047y-8c
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:08 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=vRRZfmj9JidRvsx5334H0NPDjXcsv3zx90c2L1uUT6c=; b=ezY2GnG2saHkRY0rnyQTzMNpk1
	oyPqswsT/R5ThfXCOeFx1a34Vi7DlEmTpuBVw4galMbo6+2xF9NziHuBOS6Z5tvJTbbQRwYTN4Zz2
	0cJ+tE2Yx4pmoJ9SK87fCuCz1heDVzS5mQo6ATocct1stN1HVvV4IQ/GMaKXPMCI+rgY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: add generic treewalk function
Message-Id: <E1opr7g-00047y-8c@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:16:08 +0000

commit 0d7c5d19bc27492360196e7dad2b227908564fff
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5642917e67..f78faf0c3e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1834,6 +1834,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2284,18 +2413,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2355,7 +2472,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index f7c37fe3b5..acb00ad969 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -202,6 +202,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -333,6 +334,45 @@ void read_state_buffered_data(const void *ctx, struct connection *conn,
 			      const struct xs_state_connection *sc);
 void read_state_node(const void *ctx, const void *state);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:16:19 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:16:19 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434638.687024 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7r-0001ha-PT; Tue, 01 Nov 2022 13:16:19 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434638.687024; Tue, 01 Nov 2022 13:16:19 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr7r-0001hS-LX; Tue, 01 Nov 2022 13:16:19 +0000
Received: by outflank-mailman (input) for mailman id 434638;
 Tue, 01 Nov 2022 13:16:18 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7q-0001h4-Cr
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:18 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7q-00078o-CC
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:18 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr7q-00048e-Ba
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:18 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=6An1ZfGXbNsHCqv7xz5flSq3eEXtr6vTkemzZLqkbzk=; b=qdzyoiFxsl7/Q6MCcmz8ZMArMq
	xq96mPRNFKvtiF2mSEZMF+qK3mYQg2Lfwk54jxhcv3hmQGIG91IrBkeF0ormYXmhb2cI7MrZWGBVt
	/TFP2/h0TpPGog1NISqPBnyM6IygF84/3U3+LycvlDO/SbDwsqAUaRSGstf9XYsCqwm0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: simplify check_store()
Message-Id: <E1opr7q-00048e-Ba@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:16:18 +0000

commit 70f719f52a220bc5bc987e4dd28e14a7039a176b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 47 +++++++++++++----------------------------
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f78faf0c3e..b3596c7eeb 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2456,50 +2456,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-		if (!children) {
-			log("check_store create table: ENOMEM");
-			return ENOMEM;
-		}
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2509,19 +2493,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:16:29 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:16:29 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434639.687026 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr81-0001kw-Rn; Tue, 01 Nov 2022 13:16:29 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434639.687026; Tue, 01 Nov 2022 13:16:29 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr81-0001ko-P6; Tue, 01 Nov 2022 13:16:29 +0000
Received: by outflank-mailman (input) for mailman id 434639;
 Tue, 01 Nov 2022 13:16:28 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr80-0001kf-GG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:28 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr80-00078y-FK
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:28 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr80-00049a-Eb
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:28 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=+iUO84lmWukB4beDP0vDoY8FU0eAWUYIUCd+YeeZlpo=; b=VoyQzPqDYq/ZmM3hZno1XsQWpN
	dB+t/Yd5ourwqEXBX2+mw/uLrE7BvHq2EYaHnaV0c2LpSGZihTqrh0nDieRWo/yfh9cyITn9+L9z3
	KNmTYIOs+oMYzFDWRBWrDNnHOukHtVckq1whJQkBQlqsabCGpXbj1PUTcQQ5oMxvvxmg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: use treewalk for check_store()
Message-Id: <E1opr80-00049a-Eb@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:16:28 +0000

commit a07cc0ec60612f414bedf2bafb26ec38d2602e95
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 106 ++++++++++------------------------------
 1 file changed, 26 insertions(+), 80 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b3596c7eeb..b0889186b6 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2423,18 +2423,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2448,70 +2436,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
-
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
+	struct hashtable *reachable = arg;
 
-			childnode = read_node(NULL, childname, childname);
-
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2560,29 +2507,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char *root = talloc_strdup(NULL, "/");
 	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
 
-	if (!root) {
-		log("check_store: ENOMEM");
-		return;
-	}
 	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
-		goto out_root;
+		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
- out_root:
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:16:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:16:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434641.687030 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8B-0001oA-TH; Tue, 01 Nov 2022 13:16:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434641.687030; Tue, 01 Nov 2022 13:16:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8B-0001o2-QZ; Tue, 01 Nov 2022 13:16:39 +0000
Received: by outflank-mailman (input) for mailman id 434641;
 Tue, 01 Nov 2022 13:16:38 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8A-0001ne-Ir
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:38 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8A-0007At-IH
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:38 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8A-0004AB-Hb
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:38 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=SDRaI23MkzzhCYQL+zaGY6SgodBZx2neH2HxFvKjMxY=; b=ly9KXW/lmLgjMeqfwmwfhnQFUR
	nRy5qJibvTXz5Zd7wA7xoGf4bhUZ89XA8j8C9PsOW9aAG+O2zqEoQnQKyrKVuPEPD2bZJYWdOE6g6
	WNjN6HxgB2LGEecd1ARiObIBApAWY5gqc333Tc1buVvMqZdJQmDKvsakjAlDQu9pnArc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1opr8A-0004AB-Hb@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:16:38 +0000

commit ea16962053a6849a6e7cada549ba7f8c586d85c6
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b0889186b6..fa24bcfea4 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1330,21 +1330,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1615,69 +1600,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1685,9 +1660,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1724,7 +1711,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:16:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:16:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434642.687034 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8L-0001r3-Ur; Tue, 01 Nov 2022 13:16:49 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434642.687034; Tue, 01 Nov 2022 13:16:49 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8L-0001qw-SG; Tue, 01 Nov 2022 13:16:49 +0000
Received: by outflank-mailman (input) for mailman id 434642;
 Tue, 01 Nov 2022 13:16:48 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8K-0001qW-Ln
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:48 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8K-0007Ax-LD
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:48 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8K-0004Ao-Kd
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:48 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=AeX3DM3keCGBgM5o8UddDko0WOCLPnFuSPgrbeCusGY=; b=46KuAyOdzi66Z8i7cT3DD0QnLx
	Mf4vLqhnjYuJhbGkJihcw3S4NwVL7MgtE1c+5DyCNSeFL9oVATKFALZzmHN9rUulAECb3viEyj/3g
	aq+xnTcSoYNFBsEZCER4W79UMzvaD0JswOaNdN/Tveu4O+Hk816hxss5oWb1zh5+VPrc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: use treewalk for creating node records
Message-Id: <E1opr8K-0004Ao-Kd@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:16:48 +0000

commit 297ac246a5d8ed656b349641288f3402dcc0251e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: use treewalk for creating node records
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when creating the node records during a live update.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++++++-------------------------
 1 file changed, 40 insertions(+), 65 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index fa24bcfea4..bdc14679ad 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -3088,101 +3088,76 @@ const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
 	return NULL;
 }
 
-static const char *dump_state_node_tree(FILE *fp, char *path,
-					unsigned int path_max_len)
+struct dump_node_data {
+	FILE *fp;
+	const char *err;
+};
+
+static int dump_state_node_err(struct dump_node_data *data, const char *err)
 {
-	unsigned int pathlen, childlen, p = 0;
+	data->err = err;
+	return WALK_TREE_ERROR_STOP;
+}
+
+static int dump_state_node(const void *ctx, struct connection *conn,
+			   struct node *node, void *arg)
+{
+	struct dump_node_data *data = arg;
+	FILE *fp = data->fp;
+	unsigned int pathlen;
 	struct xs_state_record_header head;
 	struct xs_state_node sn;
-	TDB_DATA key, data;
-	const struct xs_tdb_record_hdr *hdr;
-	const char *child;
 	const char *ret;
 
-	pathlen = strlen(path) + 1;
-
-	set_tdb_key(path, &key);
-	data = tdb_fetch(tdb_ctx, key);
-	if (data.dptr == NULL)
-		return "Error reading node";
-
-	/* Clean up in case of failure. */
-	talloc_steal(path, data.dptr);
-
-	hdr = (void *)data.dptr;
+	pathlen = strlen(node->name) + 1;
 
 	head.type = XS_STATE_TYPE_NODE;
 	head.length = sizeof(sn);
 	sn.conn_id = 0;
 	sn.ta_id = 0;
 	sn.ta_access = 0;
-	sn.perm_n = hdr->num_perms;
+	sn.perm_n = node->perms.num;
 	sn.path_len = pathlen;
-	sn.data_len = hdr->datalen;
-	head.length += hdr->num_perms * sizeof(*sn.perms);
+	sn.data_len = node->datalen;
+	head.length += node->perms.num * sizeof(*sn.perms);
 	head.length += pathlen;
-	head.length += hdr->datalen;
+	head.length += node->datalen;
 	head.length = ROUNDUP(head.length, 3);
 
 	if (fwrite(&head, sizeof(head), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node head error");
 	if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node state error");
 
-	ret = dump_state_node_perms(fp, hdr->perms, hdr->num_perms);
+	ret = dump_state_node_perms(fp, node->perms.p, node->perms.num);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
+
+	if (fwrite(node->name, pathlen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node path error");
 
-	if (fwrite(path, pathlen, 1, fp) != 1)
-		return "Dump node path error";
-	if (hdr->datalen &&
-	    fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1)
-		return "Dump node data error";
+	if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node data error");
 
 	ret = dump_state_align(fp);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
 
-	child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen;
-
-	/*
-	 * Use path for constructing children paths.
-	 * As we don't write out nodes without having written their parent
-	 * already we will never clobber a part of the path we'll need later.
-	 */
-	pathlen--;
-	if (path[pathlen - 1] != '/') {
-		path[pathlen] = '/';
-		pathlen++;
-	}
-	while (p < hdr->childlen) {
-		childlen = strlen(child) + 1;
-		if (pathlen + childlen > path_max_len)
-			return "Dump node path length error";
-		strcpy(path + pathlen, child);
-		ret = dump_state_node_tree(fp, path, path_max_len);
-		if (ret)
-			return ret;
-		p += childlen;
-		child += childlen;
-	}
-
-	talloc_free(data.dptr);
-
-	return NULL;
+	return WALK_TREE_OK;
 }
 
 const char *dump_state_nodes(FILE *fp, const void *ctx)
 {
-	char *path;
-
-	path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX + 1);
-	if (!path)
-		return "Path buffer allocation error";
+	struct dump_node_data data = {
+		.fp = fp,
+		.err = "Dump node walk error"
+	};
+	struct walk_funcs walkfuncs = { .enter = dump_state_node };
 
-	strcpy(path, "/");
+	if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data))
+		return data.err;
 
-	return dump_state_node_tree(fp, path, XENSTORE_ABS_PATH_MAX + 1);
+	return NULL;
 }
 
 void read_state_global(const void *ctx, const void *state)
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:17:00 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:17:00 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434643.687038 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8W-0001tz-1F; Tue, 01 Nov 2022 13:17:00 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434643.687038; Tue, 01 Nov 2022 13:17:00 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8V-0001tp-U5; Tue, 01 Nov 2022 13:16:59 +0000
Received: by outflank-mailman (input) for mailman id 434643;
 Tue, 01 Nov 2022 13:16:58 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8U-0001tU-P7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:58 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8U-0007B7-OO
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:58 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8U-0004Bl-Nc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:16:58 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Oq22E2J5er9ojZAkcP6HxZQdnj0I+s5HSvGj/XNPwLE=; b=6/G0cuP6kIbjrF1zUJuB+yhf1F
	D298I+qS3QE/btI4O1TA6Qud3ZhsC2y03D9lR85AaxnKt4w9dn9736+SbHIbaByRh5MzZeYYvsOhx
	3gR0P0PZ7yXbubWcru+gyzOeWjCrGGfNPL7Q0+h1OTx6lTLPWFHlVbY7rmeSWNqdUqA4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1opr8U-0004Bl-Nc@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:16:58 +0000

commit 755d3f9debf8879448211fffb018f556136f6a79
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 84 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 80 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index bdc14679ad..13e48aaa73 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -80,6 +80,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -753,7 +754,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -796,7 +797,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1647,7 +1648,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1711,7 +1712,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2618,6 +2619,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2642,6 +2645,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 #ifndef NO_LIVE_UPDATE
@@ -2721,7 +2725,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2757,6 +2761,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index acb00ad969..37006d508d 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -240,6 +240,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(bool live_update);
 struct connection *new_connection(const struct interface_funcs *funcs);
 struct connection *get_connection_by_id(unsigned int conn_id);
@@ -284,6 +287,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 98b401fdec..84b7817cd5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -227,10 +227,64 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		set_tdb_key(node->name, &key);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -883,15 +937,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -952,23 +1006,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -986,15 +1028,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1113,7 +1155,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 7fe0a21d9e..b38c82991d 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -62,7 +62,7 @@ const char *get_implicit_path(const struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:17:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:17:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434645.687042 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8g-0001yi-3s; Tue, 01 Nov 2022 13:17:10 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434645.687042; Tue, 01 Nov 2022 13:17:10 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8g-0001ya-1A; Tue, 01 Nov 2022 13:17:10 +0000
Received: by outflank-mailman (input) for mailman id 434645;
 Tue, 01 Nov 2022 13:17:08 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8e-0001yK-SC
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:08 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8e-0007BX-RV
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:08 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8e-0004Co-Qk
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:08 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0pd9AdDGAM2hCXnaUPF639qhMDVud6UGA92wwrJpVOk=; b=3UylC944y6XDannIa+ijBfclnZ
	bzKWkAZcwr96WxgyPz1DFgngcuz931IQPY9EC8y/aquQ5TfqMRr4KQAVcwrpIVpXQ/GhZnK6iI2aq
	dOPpvXHiKbSro+WGg+RkxM7Qrz4qPsqibdfEBNgfcDZSRHiWgbDGwah2RTF2JmHncn9c=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: make the internal memory data base the default
Message-Id: <E1opr8e-0004Co-Qk@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:17:08 +0000

commit d174fefa90487ddd25ebc618028f67b2e8a1f795
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 2d9ab6f1c5..04e351ca29 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -222,9 +222,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom->guest_domid = domid;
     dom->cmdline = xc_dom_strdup(dom, cmdline);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 13e48aaa73..36fb4a8328 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2308,7 +2308,7 @@ static void accept_connection(int sock)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2618,7 +2618,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2644,7 +2645,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2725,7 +2726,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2759,7 +2761,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:17:20 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:17:20 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434646.687045 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8q-00021T-5D; Tue, 01 Nov 2022 13:17:20 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434646.687045; Tue, 01 Nov 2022 13:17:20 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr8q-00021M-2d; Tue, 01 Nov 2022 13:17:20 +0000
Received: by outflank-mailman (input) for mailman id 434646;
 Tue, 01 Nov 2022 13:17:19 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8o-000218-Uy
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:18 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8o-0007Be-UK
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:18 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8o-0004DV-Tc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:18 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=TDA8WIaD1FnuVtKxTwStA8yPiSBvKogpqYtCqjJI+fw=; b=C5luGkuRiVMXEPFieDW3lB24c6
	RrYBzCWytgNXtceWPMJ73jEjFw7mP0OVNNhInppxjgNgTQDSbsYULL1lAB4I6tLiLg/Fyeqa53w05
	A8NbwggEjKFnN6euHf8EZT+pZbKuVAbUGkb1TlFxja02nMu+vmWCc8oqdYcOCD7t3SCw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] docs: enhance xenstore.txt with permissions description
Message-Id: <E1opr8o-0004DV-Tc@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:17:18 +0000

commit d084d2c6dff7044956ebdf83a259ad6081a1d921
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 988ef89cba..44428ae3a7 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:17:30 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:17:30 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434647.687050 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr90-00024F-6u; Tue, 01 Nov 2022 13:17:30 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434647.687050; Tue, 01 Nov 2022 13:17:30 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr90-000247-4E; Tue, 01 Nov 2022 13:17:30 +0000
Received: by outflank-mailman (input) for mailman id 434647;
 Tue, 01 Nov 2022 13:17:29 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8z-000240-1V
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:29 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8z-0007Bn-0x
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:29 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr8z-0004EQ-0M
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:29 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sZNOt/ClaYRXDA8fmRdnyz3nSjQqB6QBQHZB5U+IXY4=; b=l5Eh0pSkEUcXqM1K+oIFz37xp7
	W/k//DwBz1Tu881i40lFym0ahKKxXTI1ziE68JR5SLVxB65Wk01H0uz52xpV6UxDQi8L9H9TMQxFj
	70ZhrJ0YOrNDWLPSaWDg1fDKbqtbKT5c2PRmbiXrNhB3OTtA+hh7h1LMUcrvW9qrq1d0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1opr8z-0004EQ-0M@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:17:29 +0000

commit db471408edd46af403b8bd44d180a928ad7fbb80
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 20e67b1427..70f0c83de4 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -87,10 +87,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; SymbolMap.iter (fun _ -> recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid _ node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = SymbolMap.map walk node.children }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			SymbolMap.map walk node.children |> SymbolMap.filter is_valid } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -444,11 +455,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:17:40 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:17:40 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434648.687054 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr9A-00026x-8U; Tue, 01 Nov 2022 13:17:40 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434648.687054; Tue, 01 Nov 2022 13:17:40 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr9A-00026p-5k; Tue, 01 Nov 2022 13:17:40 +0000
Received: by outflank-mailman (input) for mailman id 434648;
 Tue, 01 Nov 2022 13:17:39 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr99-00026d-6X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:39 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr99-0007CH-5i
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:39 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr99-0004F1-3C
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:39 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=xnwdGRyY5FG4nNXk85oteZ/zF7M2hX78+q+Yx6SCEQg=; b=K5aS1CHs7poijpnO5ro66rxpRE
	mtExD5PzwCg2SmJEF3Ov4JJyoP3Mmcw8e62YPH3SBU8YTFJZVesxzG+KjWgxNiDiu8KpzAGmJP0tj
	n3eg6g4YDo+AjwXT0yHrlJEjopQMfFTshjYMRZ91reUeqZiM77v4ZNIaq5BBsntN0LCc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1opr99-0004F1-3C@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:17:39 +0000

commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 6781088387..72a79e9328 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -723,7 +723,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:17:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:17:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434649.687058 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr9K-0002Ao-A5; Tue, 01 Nov 2022 13:17:50 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434649.687058; Tue, 01 Nov 2022 13:17:50 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr9K-0002Ah-7D; Tue, 01 Nov 2022 13:17:50 +0000
Received: by outflank-mailman (input) for mailman id 434649;
 Tue, 01 Nov 2022 13:17:49 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr9J-0002A7-9F
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:49 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr9J-0007CL-8g
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:49 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr9J-0004Fz-7v
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:49 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=QhtR17oXbWdAyKBL5sUe1FuxkAij8eCL51aIkzaunMI=; b=SnRdO0zPmoiYzaedmzc9kOygBU
	dxD2uMCM9GMCDABfF62r4kDU9VqXrJiF6JUlQ60vn5UmWLPoEPL31iAvNI0sAmT6hvaTLID7ru3FD
	QLbDUFfHLUpwTxJAfzkKQ6xRXxYUnd3nGqp774fow2Q9DW6xglslZleU7W+Cyv1feJdQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: fix deleting node in transaction
Message-Id: <E1opr9J-0004Fz-7v@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:17:49 +0000

commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 3e3eb47326..7ffe21bb52 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -418,7 +418,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 13:18:00 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 13:18:00 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434650.687062 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr9U-0002Dh-Bl; Tue, 01 Nov 2022 13:18:00 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434650.687062; Tue, 01 Nov 2022 13:18:00 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opr9U-0002Da-8w; Tue, 01 Nov 2022 13:18:00 +0000
Received: by outflank-mailman (input) for mailman id 434650;
 Tue, 01 Nov 2022 13:17:59 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr9T-0002DQ-CZ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:59 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr9T-0007CP-Bq
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:59 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opr9T-0004Gk-Ay
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 13:17:59 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=kQOwBJFMv2Z2+4d7fLx/8q4ClK3hXrxzXTvWqqdO3Iw=; b=1j9GbWTaljcN9rLqlc/cKnPWGj
	pVGrWr89XWBhkksxM1DfNj0EYoUQ23U2fp8vZZxnK5RoaEYpYTHqLhQbCOBf60b9HFqkycMuD13PT
	omZLsDKIqiyoVN8ODTBbnjAPen/idXonWFfIGHBMvKlJlRsG5ud32Uzvy5dGI/18zQhM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1opr9T-0004Gk-Ay@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 13:17:59 +0000

commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 36fb4a8328..476d5c6d51 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -723,8 +723,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -842,10 +841,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 unsigned int perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 7ffe21bb52..ac854197ca 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -199,25 +200,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -240,7 +236,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -259,10 +254,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -273,9 +264,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -302,7 +294,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -321,7 +313,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -333,7 +325,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -371,100 +362,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -556,6 +537,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -579,13 +561,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -660,7 +646,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -672,11 +658,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:55:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:55:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434731.687099 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsfS-0007bd-W1; Tue, 01 Nov 2022 14:55:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434731.687099; Tue, 01 Nov 2022 14:55:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsfS-0007bW-TK; Tue, 01 Nov 2022 14:55:06 +0000
Received: by outflank-mailman (input) for mailman id 434731;
 Tue, 01 Nov 2022 14:55:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfR-0007aU-BG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfR-0000R3-9e
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfR-0000v1-8f
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=A9WJfRUGlbitRiiEr/NsmWs5/jpaPoQ/8G1bLQ/V29E=; b=xs4jmdL4a0Y48SWuKUAHmnkjZq
	f/5EYyuVbdV8ptmGWVnQZ2IUefDHncSORE8jJs6BZ9HME6byxGA5wTs1nm7iBhK8HDAOD8cA/L//u
	MtJtgD5dVCMra1nKSIQLWGwCpasK4UVInczUduL2zraeDntRKbxlicLWwwIe5n3ofhDQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] x86/vmx: Revert "VMX: use a single, global APIC access page"
Message-Id: <E1opsfR-0000v1-8f@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:55:05 +0000

commit 62e7fb702db4adaa9415ac87d95e0f461e32d9ca
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Wed Aug 24 14:16:44 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    x86/vmx: Revert "VMX: use a single, global APIC access page"
    
    The claim "No accesses would ever go to this page." is false.  A consequence
    of how Intel's APIC Acceleration works, and Xen's choice to have per-domain
    P2Ms (rather than per-vCPU P2Ms) means that the APIC page is fully read-write
    to any vCPU which is not in xAPIC mode.
    
    This reverts commit 58850b9074d3e7affdf3bc94c84e417ecfa4d165.
    
    This is XSA-412 / CVE-2022-42327.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 3b5beaf49033cddf4b2cc4e4d391b966f4203471)
---
 xen/arch/x86/hvm/vmx/vmx.c         | 59 ++++++++++++++++++++++++++++----------
 xen/arch/x86/mm/shadow/set.c       |  8 ------
 xen/arch/x86/mm/shadow/types.h     |  7 -----
 xen/include/asm-x86/hvm/vmx/vmcs.h |  1 +
 xen/include/asm-x86/mm.h           | 20 +------------
 5 files changed, 46 insertions(+), 49 deletions(-)

diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index d429d76c18..3f42765313 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -66,7 +66,8 @@ boolean_param("force-ept", opt_force_ept);
 static void vmx_ctxt_switch_from(struct vcpu *v);
 static void vmx_ctxt_switch_to(struct vcpu *v);
 
-static int alloc_vlapic_mapping(void);
+static int  vmx_alloc_vlapic_mapping(struct domain *d);
+static void vmx_free_vlapic_mapping(struct domain *d);
 static void vmx_install_vlapic_mapping(struct vcpu *v);
 static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr,
                                 unsigned int flags);
@@ -77,8 +78,6 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content);
 static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content);
 static void vmx_invlpg(struct vcpu *v, unsigned long linear);
 
-static mfn_t __read_mostly apic_access_mfn = INVALID_MFN_INITIALIZER;
-
 /* Values for domain's ->arch.hvm_domain.pi_ops.flags. */
 #define PI_CSW_FROM (1u << 0)
 #define PI_CSW_TO   (1u << 1)
@@ -402,6 +401,7 @@ static int vmx_domain_initialise(struct domain *d)
         .to   = vmx_ctxt_switch_to,
         .tail = vmx_do_resume,
     };
+    int rc;
 
     d->arch.ctxt_switch = &csw;
 
@@ -411,15 +411,24 @@ static int vmx_domain_initialise(struct domain *d)
      */
     d->arch.hvm.vmx.exec_sp = is_hardware_domain(d) || opt_ept_exec_sp;
 
+    if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 )
+        return rc;
+
     return 0;
 }
 
+static void vmx_domain_relinquish_resources(struct domain *d)
+{
+    vmx_free_vlapic_mapping(d);
+}
+
 static void domain_creation_finished(struct domain *d)
 {
     gfn_t gfn = gaddr_to_gfn(APIC_DEFAULT_PHYS_BASE);
+    mfn_t apic_access_mfn = d->arch.hvm.vmx.apic_access_mfn;
     bool ipat;
 
-    if ( !has_vlapic(d) || mfn_eq(apic_access_mfn, INVALID_MFN) )
+    if ( mfn_eq(apic_access_mfn, _mfn(0)) )
         return;
 
     ASSERT(epte_get_entry_emt(d, gfn, apic_access_mfn, 0, &ipat,
@@ -2481,6 +2490,7 @@ static struct hvm_function_table __initdata vmx_function_table = {
     .cpu_up_prepare       = vmx_cpu_up_prepare,
     .cpu_dead             = vmx_cpu_dead,
     .domain_initialise    = vmx_domain_initialise,
+    .domain_relinquish_resources = vmx_domain_relinquish_resources,
     .domain_creation_finished = domain_creation_finished,
     .vcpu_initialise      = vmx_vcpu_initialise,
     .vcpu_destroy         = vmx_vcpu_destroy,
@@ -2731,7 +2741,7 @@ const struct hvm_function_table * __init start_vmx(void)
 {
     set_in_cr4(X86_CR4_VMXE);
 
-    if ( vmx_vmcs_init() || alloc_vlapic_mapping() )
+    if ( vmx_vmcs_init() )
     {
         printk("VMX: failed to initialise.\n");
         return NULL;
@@ -3305,36 +3315,55 @@ gp_fault:
     return X86EMUL_EXCEPTION;
 }
 
-static int __init alloc_vlapic_mapping(void)
+static int vmx_alloc_vlapic_mapping(struct domain *d)
 {
     struct page_info *pg;
     mfn_t mfn;
 
-    if ( !cpu_has_vmx_virtualize_apic_accesses )
+    if ( !has_vlapic(d) || !cpu_has_vmx_virtualize_apic_accesses )
         return 0;
 
-    pg = alloc_domheap_page(NULL, 0);
+    pg = alloc_domheap_page(d, MEMF_no_refcount);
     if ( !pg )
         return -ENOMEM;
 
-    /*
-     * Signal to shadow code that this page cannot be refcounted. This also
-     * makes epte_get_entry_emt() recognize this page as "special".
-     */
-    page_suppress_refcounting(pg);
+    if ( !get_page_and_type(pg, d, PGT_writable_page) )
+    {
+        /*
+         * The domain can't possibly know about this page yet, so failure
+         * here is a clear indication of something fishy going on.
+         */
+        domain_crash(d);
+        return -ENODATA;
+    }
 
     mfn = page_to_mfn(pg);
     clear_domain_page(mfn);
-    apic_access_mfn = mfn;
+    d->arch.hvm.vmx.apic_access_mfn = mfn;
 
     return 0;
 }
 
+static void vmx_free_vlapic_mapping(struct domain *d)
+{
+    mfn_t mfn = d->arch.hvm.vmx.apic_access_mfn;
+
+    d->arch.hvm.vmx.apic_access_mfn = _mfn(0);
+    if ( !mfn_eq(mfn, _mfn(0)) )
+    {
+        struct page_info *pg = mfn_to_page(mfn);
+
+        put_page_alloc_ref(pg);
+        put_page_and_type(pg);
+    }
+}
+
 static void vmx_install_vlapic_mapping(struct vcpu *v)
 {
+    mfn_t apic_access_mfn = v->domain->arch.hvm.vmx.apic_access_mfn;
     paddr_t virt_page_ma, apic_page_ma;
 
-    if ( !has_vlapic(v->domain) || mfn_eq(apic_access_mfn, INVALID_MFN) )
+    if ( mfn_eq(apic_access_mfn, _mfn(0)) )
         return;
 
     ASSERT(cpu_has_vmx_virtualize_apic_accesses);
diff --git a/xen/arch/x86/mm/shadow/set.c b/xen/arch/x86/mm/shadow/set.c
index 87e9c6eeb2..bd6c68b547 100644
--- a/xen/arch/x86/mm/shadow/set.c
+++ b/xen/arch/x86/mm/shadow/set.c
@@ -101,14 +101,6 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type)
         owner = page_get_owner(pg);
     }
 
-    /*
-     * Check whether refcounting is suppressed on this page. For example,
-     * VMX'es APIC access MFN is just a surrogate page.  It doesn't actually
-     * get accessed, and hence there's no need to refcount it.
-     */
-    if ( pg && page_refcounting_suppressed(pg) )
-        return 0;
-
     if ( owner == dom_io )
         owner = NULL;
 
diff --git a/xen/arch/x86/mm/shadow/types.h b/xen/arch/x86/mm/shadow/types.h
index 6970e7d6ea..814a401853 100644
--- a/xen/arch/x86/mm/shadow/types.h
+++ b/xen/arch/x86/mm/shadow/types.h
@@ -276,16 +276,9 @@ int shadow_set_l4e(struct domain *d, shadow_l4e_t *sl4e,
 static void inline
 shadow_put_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
 {
-    mfn_t mfn = shadow_l1e_get_mfn(sl1e);
-
     if ( !shadow_mode_refcounts(d) )
         return;
 
-    if ( mfn_valid(mfn) &&
-         /* See the respective comment in shadow_get_page_from_l1e(). */
-         page_refcounting_suppressed(mfn_to_page(mfn)) )
-        return;
-
     put_page_from_l1e(sl1e, d);
 }
 
diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h
index 03c9ccf627..8073af323b 100644
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -58,6 +58,7 @@ struct ept_data {
 #define _VMX_DOMAIN_PML_ENABLED    0
 #define VMX_DOMAIN_PML_ENABLED     (1ul << _VMX_DOMAIN_PML_ENABLED)
 struct vmx_domain {
+    mfn_t apic_access_mfn;
     /* VMX_DOMAIN_* */
     unsigned int status;
 
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index 7bdf9c2290..e1bcea57a8 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -83,7 +83,7 @@
 #define PGC_state_offlined  PG_mask(2, 6)
 #define PGC_state_free      PG_mask(3, 6)
 #define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
-/* Page is not reference counted (see below for caveats) */
+/* Page is not reference counted */
 #define _PGC_extra        PG_shift(7)
 #define PGC_extra         PG_mask(1, 7)
 
@@ -375,24 +375,6 @@ void zap_ro_mpt(mfn_t mfn);
 
 bool is_iomem_page(mfn_t mfn);
 
-/*
- * Pages with no owner which may get passed to functions wanting to
- * refcount them can be marked PGC_extra to bypass this refcounting (which
- * would fail due to the lack of an owner).
- *
- * (For pages with owner PGC_extra has different meaning.)
- */
-static inline void page_suppress_refcounting(struct page_info *pg)
-{
-   ASSERT(!page_get_owner(pg));
-   pg->count_info |= PGC_extra;
-}
-
-static inline bool page_refcounting_suppressed(const struct page_info *pg)
-{
-    return !page_get_owner(pg) && (pg->count_info & PGC_extra);
-}
-
 struct platform_bad_page {
     unsigned long mfn;
     unsigned int order;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:55:17 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:55:17 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434733.687103 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsfd-0007tY-1W; Tue, 01 Nov 2022 14:55:17 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434733.687103; Tue, 01 Nov 2022 14:55:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsfc-0007tQ-Uw; Tue, 01 Nov 2022 14:55:16 +0000
Received: by outflank-mailman (input) for mailman id 434733;
 Tue, 01 Nov 2022 14:55:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfb-0007tF-Dr
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfb-0000R9-D4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfb-0000vY-C2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=xYnGUMaNijxcNFYSR8O2mWA5nfnxoOjhhMIuNe7m7Jg=; b=ebbsuI1QknVv3BJLJQyus8aVkx
	Os5SBGiMzasr6zEX7/t6DcyUW58Ne81MrgCTBQdAvN9lgFoRFfN/lZPX045J0z374KGjto65gx9lx
	V74J0Z3YsxCljyKf/Z9Cv2sN8ZjPE8Z7QtEbC2HVY1vaPspC79dtF7zIKNDEa0rBFoEE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1opsfb-0000vY-C2@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:55:15 +0000

commit 28ea39a4eb476f9105e1021bef1367c075feaa0b
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 1cd3cc7ea27cda7640a8d895e09617b61c265697)
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 0c8ee276f8..29947c3020 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1088,9 +1088,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -1099,7 +1098,7 @@ static int destroy_node(void *_node)
 	set_tdb_key(node->name, &key);
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -1108,7 +1107,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1130,23 +1130,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:55:27 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:55:27 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434734.687107 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsfn-0007w6-32; Tue, 01 Nov 2022 14:55:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434734.687107; Tue, 01 Nov 2022 14:55:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsfn-0007vy-0H; Tue, 01 Nov 2022 14:55:27 +0000
Received: by outflank-mailman (input) for mailman id 434734;
 Tue, 01 Nov 2022 14:55:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfl-0007vp-H2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfl-0000RR-GE
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfl-0000w8-FR
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=wmafLvAprpRm9gJp+j7AengIwca2v0muA4tHN+/CMYg=; b=Sohf0zHPP/ZF5NIIBlOJn+PNED
	8dqRyoNZDJtLwuDCbdg4Jt7km8qv2LddobDtHgLAhXJ8ZXNTgHvw+MTT59+V19UXkfemJKUw/LvOk
	57WUZZkUyx4bkZnbERTbU+Mo+a56prlReLLirKbgB6lY8jSPen3Gqo2XJcr3gtkntNtE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1opsfl-0000w8-FR@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:55:25 +0000

commit 427e86b48836a9511f57004ca367283cd85cd30f
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34)
---
 tools/xenstore/xenstored_core.c        | 23 +++++++++++++++--------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 29947c3020..e9c9695fd1 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -566,15 +566,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 unsigned int perm_for_conn(struct connection *conn,
@@ -1090,16 +1092,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	set_tdb_key(node->name, &key);
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 07d861d924..0004fa848c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -155,6 +155,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd07fb0f21..faf6c930e4 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:55:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:55:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434735.687110 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsfx-0007ym-4a; Tue, 01 Nov 2022 14:55:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434735.687110; Tue, 01 Nov 2022 14:55:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsfx-0007yf-1l; Tue, 01 Nov 2022 14:55:37 +0000
Received: by outflank-mailman (input) for mailman id 434735;
 Tue, 01 Nov 2022 14:55:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfv-0007yS-Ji
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfv-0000Ry-J1
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsfv-0000x2-IS
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=PqH9E86/51RSyzYlrclzEzrehFiK2zMfs8RuHFZBMWQ=; b=DMwwsmg57a1u8VKsCAag2tBNkh
	FtgI6rsdXqqyLmnOt5vpZTs7goBMOdA0vOjAMsUyvKGOOyxbueR9AHOXUy1hYU2SArYB8paXbXdtY
	TCRbkCtG9T6kE0PwrmMEgO6iRih6Ep/wys4l5Vr/qFgb7L7XlMhjlYhXQseZ7ZFenTEM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: split up send_reply()
Message-Id: <E1opsfv-0000x2-IS@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:55:35 +0000

commit ce6aea73f6c4c90fab2500933b3a488e2f30334b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32)
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 39 ++++-----------------
 3 files changed, 52 insertions(+), 62 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e9c9695fd1..249ad5ec6f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -767,49 +767,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -817,8 +800,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 0004fa848c..9af9af4390 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -187,6 +187,7 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index aca0a71bad..99a2c266b2 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -85,35 +85,6 @@ static const char *get_watch_path(const struct watch *watch, const char *name)
 	return path;
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
-{
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
-
-	name = get_watch_path(watch, name);
-
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
-}
-
 /*
  * Check permissions of a specific watch to fire:
  * Either the node itself or its parent have to be readable by the connection
@@ -190,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -292,7 +267,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:55:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:55:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434736.687115 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsg6-00081b-82; Tue, 01 Nov 2022 14:55:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434736.687115; Tue, 01 Nov 2022 14:55:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsg6-00081T-5D; Tue, 01 Nov 2022 14:55:46 +0000
Received: by outflank-mailman (input) for mailman id 434736;
 Tue, 01 Nov 2022 14:55:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsg5-00081N-Mg
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsg5-0000SD-M2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsg5-0000xU-LM
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ywr3jU6yqGlciNoOz+oixdC18tcuiZwzy0U+vM5DZo4=; b=Hd7eT/jMLQFDjmMpK1fkUUaD47
	1xNKSvQbHx1LFUuA4VlCXut6KJYxkFGRKi2jW2SQAFcIuFzxFlYr9NIHtgh6/+hmkm8IALefFJVHV
	Znabjg6KfE4Ddf8lriS3hDbKitAuosUHvFiBkZXHSedioxC7rmJxjcl+d3TdfAVPaydo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1opsg5-0000xU-LM@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:55:45 +0000

commit f8af1a27b00e373bfb5f5e61b14c51165a740fa4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ead062a68a9c201a95488e84750a70a107f7b317)
---
 tools/xenstore/xenstored_core.c   | 26 +++++++++++++++++---------
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c |  7 +------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 249ad5ec6f..527a1ebded 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -211,6 +211,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -254,8 +269,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
@@ -1506,18 +1520,12 @@ static struct {
  */
 void ignore_connection(struct connection *conn)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored\n", conn);
 
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 9af9af4390..e7ee87825c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -276,6 +276,8 @@ int remember_string(struct hashtable *hash, const char *str);
 
 void set_tdb_key(const char *name, TDB_DATA *key);
 
+void conn_free_buffered_data(struct connection *conn);
+
 const char *dump_state_global(FILE *fp);
 const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 				     struct xs_state_connection *sc);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index d03c7d93a9..93c4c1edcd 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -411,15 +411,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:55:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:55:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434737.687119 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsgG-00084P-9S; Tue, 01 Nov 2022 14:55:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434737.687119; Tue, 01 Nov 2022 14:55:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsgG-00084I-6k; Tue, 01 Nov 2022 14:55:56 +0000
Received: by outflank-mailman (input) for mailman id 434737;
 Tue, 01 Nov 2022 14:55:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgF-00084A-Pz
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgF-0000ST-PF
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgF-0000ya-OT
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:55:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=N7z8UJX8hmSxIdPOvCRK9CjhehUH65LHUYpW1ZGUFGk=; b=V7FUbKSJjXGacCzNZI8h3yjABd
	M73pkzHJ2P6fKOaEhiVMBVsVbDDULJr1Vc0DLIP8J1ZI1yvxYvXpjCSbVXKmXpRxa+FDoKhIcc0xA
	xHltaVZQ6WSUUWo7EVsvjNO0NM46IJ/PfX9ck49dfEpyP6jWnq/TX4Cnz4iyypuRY2hY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: reduce number of watch events
Message-Id: <E1opsgF-0000ya-OT@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:55:55 +0000

commit e26d6f4d1b389b859fb5a6570421e80e0213f92b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297)
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 527a1ebded..bf22438739 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1295,7 +1295,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1307,7 +1307,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1319,7 +1319,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1345,13 +1350,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index faf6c930e4..54432907fc 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -323,6 +327,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 99a2c266b2..205d9d8ea1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:56:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:56:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434738.687123 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsgQ-00086t-BB; Tue, 01 Nov 2022 14:56:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434738.687123; Tue, 01 Nov 2022 14:56:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsgQ-00086l-8K; Tue, 01 Nov 2022 14:56:06 +0000
Received: by outflank-mailman (input) for mailman id 434738;
 Tue, 01 Nov 2022 14:56:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgP-00086e-TB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgP-0000Sn-SQ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgP-0000zI-Rc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=GoaluqxABeEb8imuMhZ0x0K4juZXR0IZ5OsTdR1U6S4=; b=qIzQ7sNDRyx2nzextRWn9c7b/i
	JWaONchcHVoagQH3Bvq4tCjMCkH3rhGLqYy2OY22lR14x5qULcD8SXh4NT0HMdoFmA+/hLTw58gYg
	VwlqfzDNN9zg6oHSaNTr4UaZjUq21wCTfzmfm5QNNQypk6g6bZbo8Tc4SJa72H4WeR3Y=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: let unread watch events time out
Message-Id: <E1opsgP-0000zI-Rc@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:56:05 +0000

commit d08cdf0b19daf948a6b9754e90de9bc304bcd262
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 5285dcb1a5c01695c11e6397c95d906b5e765c98)
---
 tools/xenstore/xenstored_core.c | 133 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index bf22438739..45244c021c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -108,6 +108,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -211,19 +213,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -411,6 +486,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -431,10 +507,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (conn_can_read(conn) ||
 			    (conn_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -794,6 +872,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -845,6 +924,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -2201,6 +2286,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2223,6 +2311,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2236,6 +2325,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2250,7 +2372,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:U", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2300,6 +2422,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
@@ -2741,6 +2866,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 		barf("error restoring buffered data");
 
 	memcpy(bdata->buffer, data, len);
+	if (bdata->hdr.msg.type == XS_WATCH_EVENT && timeout_watch_event_msec &&
+	    domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index e7ee87825c..8a81fc693f 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -67,6 +68,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -118,6 +121,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -244,6 +248,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:56:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:56:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434739.687129 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsga-00089w-EB; Tue, 01 Nov 2022 14:56:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434739.687129; Tue, 01 Nov 2022 14:56:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsga-00089o-A1; Tue, 01 Nov 2022 14:56:16 +0000
Received: by outflank-mailman (input) for mailman id 434739;
 Tue, 01 Nov 2022 14:56:16 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsga-00089g-0Q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:16 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgZ-0000TB-Vy
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgZ-0000zk-Us
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=kx1yPaVxj63iNnryO8WAoHNrcxM2Nbn2b9KluX3J7Zk=; b=0nIfx/HLwxAHapbEk62WBElOBC
	Rx8b1ju3/hsD8A+3ZjN9Nl3tJdTMY5zA/zOgNW+5fbd2li4NMyxLRewfJq+uEXN5kLDJeOvivKOLm
	bzVhDypQpmLf2vVftzYB2GuDfSJ4kEYTMOWnuWkyAsRL4B2qCTioOfZ67luRgWaaucd0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: limit outstanding requests
Message-Id: <E1opsgZ-0000zk-Us@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:56:15 +0000

commit 49344fb86ff040bae1107e236592c2d4dc4607f3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 36de433a273f55d614c83b89c9a8972287a1e475)
---
 tools/xenstore/xenstored_core.c   | 88 +++++++++++++++++++++++++++++++++++++--
 tools/xenstore/xenstored_core.h   | 20 ++++++++-
 tools/xenstore/xenstored_domain.c | 38 ++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 +++++--
 5 files changed, 150 insertions(+), 14 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 45244c021c..488d540f3a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -107,6 +107,7 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -223,12 +224,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -244,6 +257,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -405,6 +442,7 @@ int delay_request(struct connection *conn, struct buffered_data *in,
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -418,6 +456,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -893,6 +936,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -900,7 +945,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -930,8 +976,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1740,6 +1791,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1808,6 +1860,7 @@ struct connection *new_connection(const struct interface_funcs *funcs)
 	new->is_stalled = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 	INIT_LIST_HEAD(&new->delayed);
@@ -2286,6 +2339,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2311,6 +2367,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2358,6 +2415,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2372,8 +2443,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
-				  NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
 			no_domain_init = true;
@@ -2422,6 +2493,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
@@ -2875,6 +2949,14 @@ static void add_buffered_data(struct buffered_data *bdata,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	/*
+	 * Watch events are never "outstanding", but the request causing them
+	 * are instead kept "outstanding" until all watch events caused by that
+	 * request have been delivered.
+	 */
+	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
+		domain_outstanding_inc(conn);
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 8a81fc693f..db09f463a6 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -56,6 +56,8 @@ struct xs_state_connection;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -63,6 +65,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -123,6 +136,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -191,7 +207,8 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -247,6 +264,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 93c4c1edcd..850085a92c 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -78,6 +78,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -183,8 +186,12 @@ static bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	return (intf->req_cons != intf->req_prod);
 }
@@ -331,7 +338,7 @@ static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -392,9 +399,6 @@ static int new_domain(struct domain *domain, int port, bool restore)
 	domain->conn->domain = domain;
 	domain->conn->id = domain->domid;
 
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
-
 	return 0;
 }
 
@@ -938,6 +942,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 1e929b8f8c..4f51b00529 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,6 +64,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 205d9d8ea1..0755ffa375 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -269,8 +272,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	trace_create(watch, "watch");
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:56:27 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:56:27 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434740.687131 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsgl-0008DQ-Ga; Tue, 01 Nov 2022 14:56:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434740.687131; Tue, 01 Nov 2022 14:56:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsgl-0008DI-D5; Tue, 01 Nov 2022 14:56:27 +0000
Received: by outflank-mailman (input) for mailman id 434740;
 Tue, 01 Nov 2022 14:56:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgk-0008D2-3P
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgk-0000TG-2q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:26 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgk-00010J-28
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:26 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=PLgRwQ2ThYZr1F2SLqCzGeuXlneqbc52mMqouxZjBeo=; b=Ve6clNLkqZqW1O55wZdtZd2d2O
	HjuPGVzDGIsJgK3o+1uK9lj//N13wB1f8ErlS9M0CbrIhWZfV/aN3Tt2ibOoaD9nY0y/J4OnmOQGz
	O24AXMN0YGGAy6/IKRtW4TZ3tpiLe8c5xMOclYpvB1+/4iDkmcQzovATOwsaIhwUA5os=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1opsgk-00010J-28@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:56:26 +0000

commit b270ad4a7ebe3409337bf3730317af6977c38197
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2)
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 488d540f3a..f1fa97b8cf 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -916,6 +916,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -948,7 +949,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -970,12 +971,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index db09f463a6..b9b50e81c7 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -62,6 +62,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:56:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:56:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434741.687135 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsgv-0008GO-HC; Tue, 01 Nov 2022 14:56:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434741.687135; Tue, 01 Nov 2022 14:56:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsgv-0008GH-El; Tue, 01 Nov 2022 14:56:37 +0000
Received: by outflank-mailman (input) for mailman id 434741;
 Tue, 01 Nov 2022 14:56:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgu-0008G5-6p
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgu-0000Te-6A
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsgu-000112-5R
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ZFv0vZWdGTC87c19ZlWUd8F9US7MgeqCAC+tolmj8sw=; b=mZ2l2lgSgMyfJcL+HeJwRFPBFc
	BaLXwYUhmLAsDqubzY5STk1JtBDqOPJ0rpGJIOhNpQRDMXHSeQpCI1S3S3efM20C1v/gv2pDUlv2N
	elyz2ysUDNhmro5lDxuyPlcFsCxsX8U3ofp8E5ML9Q1GJ1TdRdmoqLsoiIElunzB5qNA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: fix connection->id usage
Message-Id: <E1opsgu-000112-5R@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:56:36 +0000

commit 787241f55216d34ca025c835c6a2096d7664d711
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831)
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 7b4300ef77..adb8d51b04 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -891,7 +891,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	unsigned int cmd, num, off;
 	char **vec = NULL;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	off = get_string(in, 0);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index b9b50e81c7..b1a70488b9 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -123,7 +123,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this connection ignored? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 54432907fc..ee1b09031a 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -477,7 +477,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:56:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:56:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434742.687139 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsh5-0008J6-JB; Tue, 01 Nov 2022 14:56:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434742.687139; Tue, 01 Nov 2022 14:56:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsh5-0008Iy-GM; Tue, 01 Nov 2022 14:56:47 +0000
Received: by outflank-mailman (input) for mailman id 434742;
 Tue, 01 Nov 2022 14:56:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsh4-0008Io-Ab
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsh4-0000VN-9q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsh4-00011Z-8d
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=VmTKf1otiLRSsAMm6pC6UQ59/8yrGZCC/3fg2E426vU=; b=AYmmF2Qnu3ofWglYoC/IgFV57V
	3+mO9iS6bfZ4ibt1vnlexQiwRuNin6kFqszVJEd+dfgHraml2IVFOWMWok5YINndHc8SdWOgwLkID
	5Tk5VppKLS7D7RKAEV0P6ARXjXq615T3bc0ZVQWyld4KkJ9wcUHlx2UTWwaQJviLZ2k4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1opsh4-00011Z-8d@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:56:46 +0000

commit 717460e062dfe13a69cb01f518dd7b65d39376ef
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit dbef1f7482894c572d90cd73d99ed689c891e863)
---
 tools/xenstore/xenstored_core.c        |  43 +++++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 4 files changed, 109 insertions(+), 51 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f1fa97b8cf..692d863fce 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -638,7 +638,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -660,7 +660,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1272,13 +1272,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1328,8 +1332,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1614,10 +1622,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
+
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
 
-	if (write_node(conn, node, false))
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
@@ -3122,7 +3147,9 @@ void read_state_node(const void *ctx, const void *state)
 	set_tdb_key(name, &key);
 	if (write_node_raw(NULL, &key, node, true))
 		barf("write node error restoring node");
-	domain_entry_inc(&conn, node);
+
+	if (domain_entry_inc(&conn, node))
+		barf("node accounting error restoring node");
 
 	talloc_free(node);
 }
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 850085a92c..260952e090 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -363,6 +364,18 @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid)
 	return domain ? : alloc_domain(ctx, domid);
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port, bool restore)
 {
 	int rc;
@@ -782,30 +795,28 @@ void domain_deinit(void)
 		xenevtchn_unbind(xce_handle, virq_port);
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -841,7 +852,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -851,8 +862,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -871,25 +888,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -899,13 +916,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4f51b00529..d6519904d8 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -54,10 +54,10 @@ const char *get_implicit_path(const struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ee1b09031a..86caf6c398 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -519,8 +519,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:56:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:56:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434743.687143 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opshF-0008M4-Ke; Tue, 01 Nov 2022 14:56:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434743.687143; Tue, 01 Nov 2022 14:56:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opshF-0008Lw-I0; Tue, 01 Nov 2022 14:56:57 +0000
Received: by outflank-mailman (input) for mailman id 434743;
 Tue, 01 Nov 2022 14:56:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshE-0008Lh-Dp
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshE-0000VR-DB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshE-000120-CN
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:56:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=cq98dzgdMJ6/p1Lt/9FL1lT3OhRe71lh+eFQpQ3t9mM=; b=w0q1rd8lFEcsKdKwzZmG36+Q97
	RT1Ya6kNBFdVeyQpbq2B3gtloXmvLhMr76dec0fmJxc9Mf9iq13lm4r5FyzQW+PimtxXO3UNZrq5e
	A337aTuPMQeMCgO70uvRKoh8sVjXWvKnujcjGlHu1R6aht+WZ1XlCN5A/EdpOA60FzyM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1opshE-000120-CN@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:56:56 +0000

commit 7017cfefc455db535054ebc09124af8101746a4a
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 268369d8e322d227a74a899009c5748d7b0ea142)
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  1 +
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index a16e0c3807..bafc90e2f6 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -63,4 +63,8 @@
 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 692d863fce..f835aa1b2f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -106,6 +106,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
 
@@ -595,6 +596,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -616,14 +618,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -638,19 +639,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -767,7 +785,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -829,7 +847,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1235,7 +1253,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1509,7 +1527,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1539,7 +1557,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2384,6 +2402,8 @@ static void usage(void)
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2468,6 +2488,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index b1a70488b9..245f925823 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -268,6 +268,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 86caf6c398..7bd41eb475 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -260,6 +263,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -297,6 +305,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:57:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:57:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434744.687149 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opshP-0008Qv-Ok; Tue, 01 Nov 2022 14:57:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434744.687149; Tue, 01 Nov 2022 14:57:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opshP-0008Qm-L1; Tue, 01 Nov 2022 14:57:07 +0000
Received: by outflank-mailman (input) for mailman id 434744;
 Tue, 01 Nov 2022 14:57:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshO-0008QU-Gt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:06 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshO-0000Vl-GJ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:06 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshO-00012g-Fb
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ghijQeZ9TfaEypIiYA04va0jebx39sdXvSjSHa6cPWU=; b=DT+y/n5RehZHGrtE2qjLza5PxN
	cvzTINHyYkO0rRvhFYGHlYQIf5TwGQZ7OZDoayIiclLEA60r7PT6jpUtikWWu4HFXFeWIXrTcxAND
	/2mtJKHeE9gpGcx2084vPaUEqjTHGZHNIjKULKZlV4aQDk0y9L+v4FoCdkXCkfGkTlN0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1opshO-00012g-Fb@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:57:06 +0000

commit 2d39cf77d70b44b70f970da90187f48d2c0b3e96
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 60e2f6020dea7f616857b8fc1141b1c085d88761)
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 3 +++
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f835aa1b2f..5171d34c94 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2039,7 +2039,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -2078,7 +2079,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(bool live_update)
+void setup_structure(bool live_update)
 {
 	char *tdbname;
 
@@ -2101,6 +2102,7 @@ static void setup_structure(bool live_update)
 		manual_node("/", "tool");
 		manual_node("/tool", "xenstored");
 		manual_node("/tool/xenstored", NULL);
+		domain_entry_fix(dom0_domid, 3, true);
 	}
 
 	check_store();
@@ -2614,9 +2616,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure(live_update);
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init && !live_update) {
 		domain_init(-1);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 245f925823..2c77ec7ee0 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -231,6 +231,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(bool live_update);
 struct connection *new_connection(const struct interface_funcs *funcs);
 struct connection *get_connection_by_id(unsigned int conn_id);
 void ignore_connection(struct connection *conn);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 260952e090..f04b7aae8a 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -470,6 +470,9 @@ static struct domain *introduce_domain(const void *ctx,
 		}
 		domain->interface = interface;
 
+		if (is_master_domain)
+			setup_structure(restore);
+
 		/* Now domain belongs to its connection. */
 		talloc_steal(domain->conn, domain);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:57:17 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:57:17 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434745.687151 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opshZ-0008Tb-PW; Tue, 01 Nov 2022 14:57:17 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434745.687151; Tue, 01 Nov 2022 14:57:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opshZ-0008TT-Ma; Tue, 01 Nov 2022 14:57:17 +0000
Received: by outflank-mailman (input) for mailman id 434745;
 Tue, 01 Nov 2022 14:57:16 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshY-0008TF-Kf
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:16 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshY-0000Vp-K0
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:16 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshY-00013I-In
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:16 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=IiHwQeB7HUysN2YOfCaEzSBteBAph8Zjn+yEroDD0Cg=; b=sYzF0OZ73Peg/1pOkD3LO6dyHv
	mV8/9oyW1lMBhcPia+C9gnODSwKrkqVt2S1VcjDS9hXzU4ZJN14oWSjHhDlrh3nQ79/5Ly2ObvL+s
	7XSCs3jnFQxNhs2pbmQP/wxSpOnAEQ2j/iGQJH6xRxDtOha04pQF3M6WwafVPvHBjDWQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1opshY-00013I-In@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:57:16 +0000

commit 2e406cf5fbb817341dc860473158382057e13de5
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d4a8ec7a93faedbe54fd197db146de628459e77)
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5171d34c94..b2bf6740d4 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -109,6 +109,8 @@ int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2406,7 +2408,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2433,6 +2442,7 @@ static struct option options[] = {
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2480,7 +2490,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2488,11 +2498,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2510,7 +2525,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2561,7 +2576,10 @@ int main(int argc, char *argv[])
 						 quota_max_path_len);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2c77ec7ee0..373af18297 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -270,6 +270,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index f04b7aae8a..94fd561e9d 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -76,6 +76,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -192,6 +199,9 @@ static bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	return (intf->req_cons != intf->req_prod);
@@ -950,6 +960,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index d6519904d8..633c9a0a0a 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -61,6 +61,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:57:27 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:57:27 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434746.687154 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opshj-0008WO-Qw; Tue, 01 Nov 2022 14:57:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434746.687154; Tue, 01 Nov 2022 14:57:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opshj-0008WG-OA; Tue, 01 Nov 2022 14:57:27 +0000
Received: by outflank-mailman (input) for mailman id 434746;
 Tue, 01 Nov 2022 14:57:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshi-0008Vt-OV
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshi-0000Vy-N6
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:26 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshi-00013h-ML
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:26 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=1lGpgBvXr9Bgbl1xXjeZSlGPTaa9W9AgGmn48W4qWVE=; b=PHruH2GPzv/pc67f4yR02pjS40
	pvqQBZOposv7D+XeuGvautfB6bIzFW8S7s7kc21p4fRJVYyaaTajfJWENDrrJf2gK6yzS//lDqR7r
	1gCppjcRHigsUgEkkJRe7w+wT7Gpo9R3xmDDZRz/6vIB8C9BvsXeZPHdCXYLyTx+uXUk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: add memory accounting for responses
Message-Id: <E1opshi-00013h-ML@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:57:26 +0000

commit 30c8e752f66f681b5c731a637c26510ae5f35965
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    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 f6d00133643a524d2138c9e3f192bbde719050ba)
---
 tools/xenstore/xenstored_core.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b2bf6740d4..ecab6cfbbe 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -260,6 +260,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -938,11 +940,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -1007,6 +1012,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
@@ -3039,6 +3049,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 	 */
 	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
 		domain_outstanding_inc(conn);
+	/*
+	 * We are restoring the state after Live-Update and the new quota may
+	 * be smaller. So ignore it. The limit will be applied for any resource
+	 * after the state has been fully restored.
+	 */
+	domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:57:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:57:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434747.687159 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsht-00007o-ST; Tue, 01 Nov 2022 14:57:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434747.687159; Tue, 01 Nov 2022 14:57:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsht-00007f-Pj; Tue, 01 Nov 2022 14:57:37 +0000
Received: by outflank-mailman (input) for mailman id 434747;
 Tue, 01 Nov 2022 14:57:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshs-00007S-R1
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshs-0000WQ-QL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opshs-000146-Pc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Jq6wHb9T8UsA3wilqvm9upeDn0e7tmhce5X88I0OrwE=; b=TS8O5MEy2644/c5SgQxpUSDHX+
	bMsZMhWa0TnkHLCa/6tD/3KTLDSPDIEFCDyyF1Jf+S2OidNL+3+8RB5Ug7q0/sVvjlVzL/5Rw92b/
	kDcnTgNX28Ez+KsOW968x7O7oeQWuzmbWAfM8WfTeolC55j1n+g9PKcO3LJibr0CGHyQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: add memory accounting for watches
Message-Id: <E1opshs-000146-Pc@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:57:36 +0000

commit bce985745cde48a339954759677b77d3eeec41f3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    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 7f9978a2cc37aaffab2fb09593bc598c0712a69b)
---
 tools/xenstore/xenstored_core.c  |  1 +
 tools/xenstore/xenstored_watch.c | 13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ecab6cfbbe..d86942f5aa 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -463,6 +463,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 0755ffa375..fdf9b2d653 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -211,7 +211,7 @@ static int check_watch_path(struct connection *conn, const void *ctx,
 }
 
 static struct watch *add_watch(struct connection *conn, char *path, char *token,
-			       bool relative)
+			       bool relative, bool no_quota_check)
 {
 	struct watch *watch;
 
@@ -222,6 +222,9 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	watch->token = talloc_strdup(watch, token);
 	if (!watch->node || !watch->token)
 		goto nomem;
+	if (domain_memory_add(conn->id, strlen(path) + strlen(token),
+			      no_quota_check))
+		goto nomem;
 
 	if (relative)
 		watch->relative_path = get_implicit_path(conn);
@@ -265,7 +268,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (domain_watch(conn) > quota_nb_watch_per_domain)
 		return E2BIG;
 
-	watch = add_watch(conn, vec[0], vec[1], relative);
+	watch = add_watch(conn, vec[0], vec[1], relative, false);
 	if (!watch)
 		return errno;
 
@@ -296,6 +299,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -311,6 +316,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
@@ -373,7 +380,7 @@ void read_state_watch(const void *ctx, const void *state)
 	if (!path)
 		barf("allocation error for read watch");
 
-	if (!add_watch(conn, path, token, relative))
+	if (!add_watch(conn, path, token, relative, true))
 		barf("error adding watch");
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:57:48 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:57:48 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434748.687162 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsi3-0000As-Ty; Tue, 01 Nov 2022 14:57:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434748.687162; Tue, 01 Nov 2022 14:57:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsi3-0000Ae-RK; Tue, 01 Nov 2022 14:57:47 +0000
Received: by outflank-mailman (input) for mailman id 434748;
 Tue, 01 Nov 2022 14:57:47 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsi2-0000AU-W0
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsi2-0000WU-VL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsi2-00014g-Sv
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ea7kkUBqsJlxY+Ihc/1zv1CBybFWkttH/CnA0XWZOrI=; b=0VpJIA1tZjJJck6rl51RWgufSM
	o5Eem1wlflO2Ak368zKjQnDNCTVJXqQx5x5o/e7s/ImGCzEpCurCfXuxOv5s4ijgmqEHSZThOm18r
	LWWkyUy3G7KtSW08wupB7oRsryJhEwim87cK8rb7q8kjIQk2d1y7zZYeY8Y4syARambk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: add memory accounting for nodes
Message-Id: <E1opsi2-00014g-Sv@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:57:46 +0000

commit 578d422af0b444a9e437dd0ceddf2049364f1a40
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    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 d86942f5aa..16504de420 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -591,6 +591,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.
@@ -644,9 +755,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. */
@@ -715,12 +832,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;
 }
 
@@ -1222,7 +1336,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;
 	}
@@ -1295,6 +1409,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;
 
@@ -1303,17 +1418,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);
 
 	/*
@@ -1365,7 +1480,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;
 			}
 		}
@@ -2291,7 +2406,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);
 		}
 	}
 
@@ -3149,6 +3264,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 373af18297..da9ecce67f 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -176,6 +176,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 */
@@ -198,6 +203,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. */
@@ -306,6 +314,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 7bd41eb475..ace9a11d77 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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:57:58 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:57:58 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434749.687168 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsiE-0000EY-1e; Tue, 01 Nov 2022 14:57:58 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434749.687168; Tue, 01 Nov 2022 14:57:58 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsiD-0000EQ-Uf; Tue, 01 Nov 2022 14:57:57 +0000
Received: by outflank-mailman (input) for mailman id 434749;
 Tue, 01 Nov 2022 14:57:57 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiD-0000ED-2e
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:57 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiD-0000WY-1z
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:57 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiD-000155-1Q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:57:57 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=oB2hY14R4nmJqNGsof7F5+7mszoftciigN5YQQlqqcE=; b=g7904GQ8un0ZGGfaqSA7szVrjk
	gDsZkV1qSwmBKdWrX95F0Qpsyl2W3V32JBEWCfgT0+7Cb5+KVgrUDZTnWDHBPfvLYnUn9wZp4a1kS
	1ESdlJQLC3MdpavxgMUzGGq7t72jniVWTTqNfYFBwpkyFABULXTFfi3xGNQG5dCdstpQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: add exports for quota variables
Message-Id: <E1opsiD-000155-1Q@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:57:57 +0000

commit 0a67b4eef104c36bef52990e413ef361acc8183c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 1da16d5990b5f7752657fca3e948f735177ea9ad)
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index da9ecce67f..bfd3fc1e9d 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -275,6 +275,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ace9a11d77..28774813de 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static struct accessed_node *find_accessed_node(struct transaction *trans,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index fdf9b2d653..85362bcce3 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:58:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:58:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434750.687171 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsiO-0000Hl-2k; Tue, 01 Nov 2022 14:58:08 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434750.687171; Tue, 01 Nov 2022 14:58:08 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsiN-0000Hd-WD; Tue, 01 Nov 2022 14:58:08 +0000
Received: by outflank-mailman (input) for mailman id 434750;
 Tue, 01 Nov 2022 14:58:07 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiN-0000HV-5s
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:07 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiN-0000Wp-5F
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:07 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiN-00015g-4Q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:07 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=92kwOmeCzboWc7Gnl5+PtpBmbj3RdxfGM0HhNoJaOvY=; b=E52lsEhZJvKRca1RvfN0JJtnnQ
	AanAHx4aCx1821CAVvOYfwrE6zDJBMSLSRx5FqmjPpHgJLA0yG3UtUgnJB1S+TslUfJBzwu9aP3EP
	qyBYNUO/5DUaWdpjEgGGyRU6FqcAIFY5s5hP/c3ehmG112ktSWKzsKUR0tMb6eMqz3v4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1opsiN-00015g-4Q@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:58:07 +0000

commit b584b9b95687655f4f9f5c37fea3b1eea3f32886
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 334dc8b6fd..a7d006519a 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -366,6 +366,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index adb8d51b04..1031a81c38 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -196,6 +196,115 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "path-max", &quota_max_path_len, "Max. length of a node path" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 #ifdef __MINIOS__
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
@@ -847,6 +956,8 @@ static struct cmd_s cmds[] = {
 	{ "memreport", do_control_memreport, "[<file>]" },
 #endif
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 94fd561e9d..e7c6886ccf 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -345,6 +346,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 633c9a0a0a..904faa923a 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -87,6 +87,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:58:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:58:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434752.687175 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsiY-0000KY-49; Tue, 01 Nov 2022 14:58:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434752.687175; Tue, 01 Nov 2022 14:58:18 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsiY-0000KQ-1U; Tue, 01 Nov 2022 14:58:18 +0000
Received: by outflank-mailman (input) for mailman id 434752;
 Tue, 01 Nov 2022 14:58:17 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiX-0000KI-8a
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:17 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiX-0000Wt-7w
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:17 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsiX-000167-7P
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:17 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9+i+2aIkSYTbALoIERbHzpditAXkGD1KZG4tMGCQiW8=; b=HU+HNi2sqHrFwXMQXcMExyqojA
	iafuNYQALtZxEJ1fTSoNGBm89hzup3OiwnqJ5SovAhVBOhBccOjmvmr57c3z2Nr5aCN1SsFXDnVoQ
	FFysf3aSetSWUUUAQNTBNutW23u/s1QW3VFC33Sa05eDRGIf2Hu/C3Nh1byn3ECOtx+w=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1opsiX-000167-7P@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:58:17 +0000

commit b0e95b451225de4db99bbe0b8dc79fdf08873e9e
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 84734955d4bf629ba459a74773afcde50a52236f)
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ebe18b8e31..6b06f80859 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -21,9 +21,9 @@ let xs_daemon_socket = Paths.xen_run_stored ^ "/socket"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:58:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:58:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434753.687179 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsii-0000Mv-5i; Tue, 01 Nov 2022 14:58:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434753.687179; Tue, 01 Nov 2022 14:58:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsii-0000Mn-30; Tue, 01 Nov 2022 14:58:28 +0000
Received: by outflank-mailman (input) for mailman id 434753;
 Tue, 01 Nov 2022 14:58:27 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsih-0000Mg-BI
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:27 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsih-0000Wy-Ah
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:27 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsih-00016W-A7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:27 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=FS0fJbtVdOOsqIk5noZvmLauRZhMod8FTUXqolpYXQo=; b=inZ9onuC2IqAE9CTxz6N/PP3Z4
	+CCgefq709Z+Pncejo1oRYLy98h5vzoyWtV5ULOyMkmFeoGx0uCIozLs0D4TV0D/uhJhaxbwraVOt
	ZxbvwdkXTzSPpuG80cc5RcGbr8/F7AYfFUHGyAmD3yTyyf0lgm48vrEP3ybTY0x6JcGE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1opsih-00016W-A7@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:58:27 +0000

commit ab21bb1971a7fa9308053b0686f43277f6e8a6c9
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    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 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff)
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 27790d4a5c..dd58e6979c 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -389,6 +389,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"
@@ -681,9 +682,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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:58:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:58:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434754.687183 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsit-0000QI-7n; Tue, 01 Nov 2022 14:58:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434754.687183; Tue, 01 Nov 2022 14:58:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsit-0000QA-4Y; Tue, 01 Nov 2022 14:58:39 +0000
Received: by outflank-mailman (input) for mailman id 434754;
 Tue, 01 Nov 2022 14:58:37 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsir-0000Pv-EM
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:37 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsir-0000XK-Dc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:37 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsir-00016z-D2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:37 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=xB7lcFJ6tegjs7Jbc6v9hQmLmseHux00BiO/dv3vGD8=; b=lMVtLm9WcmQczGJmuvJ3Upsjsw
	tq2ejRJLXW9Rt/RYpfe/48Sg6wrbcba8nxN8/4REpyStN6U0eMN4SVBgRKs16CdCR7/wcc4UIzrQh
	IskbTRBiJZTyTDbIwdOIg0z4riO4HPnR8bmYF3qHC+7RARsQN4fYmVaqyPONye8WK8Cg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml: GC parameter tuning
Message-Id: <E1opsir-00016z-D2@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:58:37 +0000

commit a63bbcf5318b487ca86574d7fcf916958af5ed02
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 4a8bacff20b857ca0d628ef5525877ade11f2a42)
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 6b06f80859..ba63a8147e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index d44ae673c4..3b57ad016d 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -104,6 +104,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -265,6 +266,67 @@ let to_file store cons fds file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -274,6 +336,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:58:49 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:58:49 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434755.687187 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsj3-0000TR-AN; Tue, 01 Nov 2022 14:58:49 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434755.687187; Tue, 01 Nov 2022 14:58:49 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsj3-0000TH-7j; Tue, 01 Nov 2022 14:58:49 +0000
Received: by outflank-mailman (input) for mailman id 434755;
 Tue, 01 Nov 2022 14:58:47 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsj1-0000T5-H7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:47 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsj1-0000XU-GX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:47 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsj1-00017O-Fs
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:47 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=h1UsuOscJLdPOXM7zNnUEmr8mnSMwx/nM4WnvIL6eQM=; b=mu1QFfZoWhJ3amYmhzMpurKpw6
	T31RHR81D+/L/k8ZTMgw8ebv11cnSI+AWYWIQqJvqMQO3bW11J4wMGv09+ZzJdZet4eyD4sMiNIoj
	lkrt7dM+lT0+wHlw/pFQguanGRNeuhzEBOfVf4icHoj/THvhcq4kfFZX6+TUCHzeCmSk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml/libs/xb: hide type of Xb.t
Message-Id: <E1opsj1-00017O-Fs@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:58:47 +0000

commit 8b60ad49b46f2e020e0f0847df80c768d669cdb2
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Fri Jul 29 18:53:29 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml/libs/xb: hide type of Xb.t
    
    Hiding the type will make it easier to change the implementation
    in the future without breaking code that relies on it.
    
    No functional change.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba)
---
 tools/ocaml/libs/xb/xb.ml           | 3 +++
 tools/ocaml/libs/xb/xb.mli          | 9 ++-------
 tools/ocaml/xenstored/connection.ml | 8 ++------
 3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 104d319d77..8404ddd8a6 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out
 let input_len con = Queue.length con.pkt_in
 let has_in_packet con = Queue.length con.pkt_in > 0
 let get_in_packet con = Queue.pop con.pkt_in
+let has_partial_input con = match con.partial_in with
+	| HaveHdr _ -> true
+	| NoHdr (n, _) -> n < Partial.header_size ()
 let has_more_input con =
 	match con.backend with
 	| Fd _         -> false
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 3a00da6cdd..794e35bb34 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,13 +66,7 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
-type t = {
-  backend : backend;
-  pkt_in : Packet.t Queue.t;
-  pkt_out : Packet.t Queue.t;
-  mutable partial_in : partial_buf;
-  mutable partial_out : string;
-}
+type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
 val queue : t -> Packet.t -> unit
@@ -97,6 +91,7 @@ val has_output : t -> bool
 val peek_output : t -> Packet.t
 val input_len : t -> int
 val has_in_packet : t -> bool
+val has_partial_input : t -> bool
 val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 65f99ea6f2..38b47363a1 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -125,9 +125,7 @@ let get_perm con =
 let set_target con target_domid =
 	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
 
-let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with
-	| Xenbus.Xb.Xenmmap _ -> true
-	| _ -> false
+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
 let send_reply con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
@@ -280,9 +278,7 @@ let get_transaction con tid =
 
 let do_input con = Xenbus.Xb.input con.xb
 let has_input con = Xenbus.Xb.has_in_packet con.xb
-let has_partial_input con = match con.xb.Xenbus.Xb.partial_in with
-	| HaveHdr _ -> true
-	| NoHdr (n, _) -> n < Xenbus.Partial.header_size ()
+let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:58:59 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:58:59 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434756.687190 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjD-0000Wg-C2; Tue, 01 Nov 2022 14:58:59 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434756.687190; Tue, 01 Nov 2022 14:58:59 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjD-0000WY-9K; Tue, 01 Nov 2022 14:58:59 +0000
Received: by outflank-mailman (input) for mailman id 434756;
 Tue, 01 Nov 2022 14:58:57 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjB-0000WJ-K7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:57 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjB-0000XY-JX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:57 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjB-00019N-Iu
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:58:57 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NZo/tRsncWijHohl/ABaBuEd9Z4mkAwfKJjcWEHbrAA=; b=v9MLxRGCuDuvbuyouKeW9dqkpT
	RbZtpbzTgX1uYD1DQ4TL/lyIdzTqcRT7TX28hiZCbg9uxW0ARWMymzLEjQD8t6IC2V3kVM3apoDbX
	IbNSfA/ml5Mk3Sg92CPuC6hlS+vux23sEgbJsEa2KSZcXk1qrO8zidBHjh0NLVQjY7jA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1opsjB-00019N-Iu@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:58:57 +0000

commit 59981b08c8ef6eed37b1171656c2a5f3b4b74012
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c0a86a462721008eca5ff733660de094d3c34bc7)
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  4 +---
 tools/ocaml/xenstored/process.ml    | 15 +++++++--------
 5 files changed, 20 insertions(+), 42 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 38b47363a1..cc20e047d2 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,9 +277,7 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
@@ -307,7 +305,7 @@ let is_bad con = match con.dom with None -> false | Some dom -> Domain.is_bad_do
    Restrictions below can be relaxed once xenstored learns to dump more
    of its live state in a safe way *)
 let has_extra_connection_data con =
-	let has_in = has_input con || has_partial_input con in
+	let has_in = has_partial_input con in
 	let has_out = has_output con in
 	let has_socket = con.dom = None in
 	let has_nondefault_perms = make_perm con.dom <> con.perm in
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index dd58e6979c..cbf7082137 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -195,10 +195,9 @@ let parse_live_update args =
 			| _ when Unix.gettimeofday () < t.deadline -> false
 			| l ->
 				warn "timeout reached: have to wait, migrate or shutdown %d domains:" (List.length l);
-				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, in: %b, out: %b, perm: %s"
+				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, out: %b, perm: %s"
 					(Connection.get_domstr con)
 					(Connection.number_of_transactions con)
-					(Connection.has_input con)
 					(Connection.has_output con)
 					(Connection.get_perm con |> Perms.Connection.to_string)
 					) l in
@@ -706,16 +705,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -725,8 +725,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:59:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:59:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434757.687195 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjN-0000Z9-Dp; Tue, 01 Nov 2022 14:59:09 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434757.687195; Tue, 01 Nov 2022 14:59:09 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjN-0000Z0-Ar; Tue, 01 Nov 2022 14:59:09 +0000
Received: by outflank-mailman (input) for mailman id 434757;
 Tue, 01 Nov 2022 14:59:07 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjL-0000Yg-N6
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:07 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjL-0000Xv-MU
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:07 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjL-0001AE-Lo
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:07 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=rEVZkhBubThctbEdlvQV7t65g6j8soKyBrCe5xHrwjs=; b=tNTVg3Y25swRHpVUmRZ9nvpatW
	aibK/TmkXdeSTo7m7YFvfkqxH8VbUCpMCvi6l6lTOspt2l6t3khF8xbGaxpKOnAD4udmWgaMt5GOX
	lgyNHHjfNiMjugTLKX1G3zr7GGFX7cI7glTNiXyGiAmCVhIN51r88Pt+WJU5Y7NEzVPM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1opsjL-0001AE-Lo@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:59:07 +0000

commit ea1567893b05df03fe65657f0a25211a6a9ff7ec
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 19171fb5d888b4467a7073e8febc5e05540956e9)
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:59:19 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:59:19 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434758.687199 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjX-0000cB-Fs; Tue, 01 Nov 2022 14:59:19 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434758.687199; Tue, 01 Nov 2022 14:59:19 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjX-0000c4-CQ; Tue, 01 Nov 2022 14:59:19 +0000
Received: by outflank-mailman (input) for mailman id 434758;
 Tue, 01 Nov 2022 14:59:17 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjV-0000bn-QI
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:17 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjV-0000Xz-Pd
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:17 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjV-0001Ag-P3
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:17 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=dtrE768tFC1P5x6SXRyQR7tYeV9vAJc8eecyydaXcLk=; b=cVeGyPMpybBhf6rU2u0jpH27ej
	8hCmF3PEFu/BFTbOjcLx1mKrsx9z/QKlQBMa8V8mRjB093kI9CPIWzh1QXkT8HI3nWS5byobISxLG
	dKWce/JfemOnikEMRklz/YFD7b3KyD8/36P295IaQU98l9sR3k9WzpkgPIjz3nl5dbcY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1opsjV-0001Ag-P3@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:59:17 +0000

commit cec3c52c287f5aee7de061b40765aca5301cf9ca
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96)
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index cc20e047d2..9624a5f9da 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -280,6 +408,7 @@ let do_input con = Xenbus.Xb.input con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -323,7 +452,7 @@ let prevents_live_update con = not (is_bad con)
 	&& (has_extra_connection_data con || has_transaction_data con)
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 3c7429fe7f..7d68c583b4 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: Connection.watch list Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -197,6 +216,16 @@ let debug cons =
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
 
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
+
 let filter ~f cons =
 	let fold _ v acc = if f v then v :: acc else acc in
 	[]
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ba63a8147e..327b6d795e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -24,6 +24,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index cbf7082137..ce39ce28b5 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -57,7 +57,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -67,8 +67,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -234,6 +235,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -342,7 +357,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -501,7 +516,7 @@ let do_watch con t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -532,7 +547,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -700,7 +715,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -728,6 +744,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 3b57ad016d..c799e20f11 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:59:29 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:59:29 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434759.687204 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjh-0000fQ-Jk; Tue, 01 Nov 2022 14:59:29 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434759.687204; Tue, 01 Nov 2022 14:59:29 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjh-0000fI-GQ; Tue, 01 Nov 2022 14:59:29 +0000
Received: by outflank-mailman (input) for mailman id 434759;
 Tue, 01 Nov 2022 14:59:27 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjf-0000f9-Sw
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:27 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjf-0000Y4-SM
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:27 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjf-0001BD-Ro
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:27 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=mORljseaZS0STZnUaFKwxLBnYJutXcn9p0kbuu+A4do=; b=HgtYlYeZ9u/gPxPNIXjFnld2G0
	KV4zoPL61jiBvVvbLrqsQUVFWBRRdEnOzbYhIX4pvxC9C7sCVAhhdRVY0FaTFZn6GJuI5ksQ9xgSb
	kyxkxD1VY14PZeELHyOWpi2TjhQFwqGbpyOqdFx/mWHvJhH5JBmzs2oP8XAQLPllkDMg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1opsjf-0001BD-Ro@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:59:27 +0000

commit a026fddf89420dd25c5a9574d88aeab7c5711f6c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c7bc20d8d123851a468402bbfc9e3330efff21ec)
---
 SUPPORT.md | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index 85726102ea..7d0cb34c8f 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -179,13 +179,18 @@ Support for running qemu-xen device model in a linux stubdomain.
 
     Status: Tech Preview
 
-## Liveupdate of C xenstored daemon
+## Xenstore
 
-    Status: Tech Preview
+### C xenstored daemon
 
-## Liveupdate of OCaml xenstored daemon
+    Status: Supported
+    Status, Liveupdate: Tech Preview
 
-    Status: Tech Preview
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+    Status, Liveupdate: Not functional
 
 ## Toolstack/3rd party
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:59:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:59:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434760.687207 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjr-0000iN-L8; Tue, 01 Nov 2022 14:59:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434760.687207; Tue, 01 Nov 2022 14:59:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsjr-0000iG-I3; Tue, 01 Nov 2022 14:59:39 +0000
Received: by outflank-mailman (input) for mailman id 434760;
 Tue, 01 Nov 2022 14:59:38 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjp-0000hu-WE
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:38 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjp-0000YR-VZ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:37 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsjp-0001Bg-Uu
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:37 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=3F7yfpATqNGTyU3vyqwOYmNsUzGJhUrEIo2JMElLEZ0=; b=DTfA7zTbV4vg1CR4035xPPycM1
	zr1qFqHizx/1lBqLFY52VYi1UQaJ4lTDy0xgme1DqwBSJuQAla8oJWV+AK7Qsbu8L9Bbl4ntTcPBS
	iFHQXx/iUvMBlkKvcp0C/XGJ/coTl9LJ1qmaQryJzRcm+D08IUOuoyBoNVqlH5b4G51Y=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1opsjp-0001Bg-Uu@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:59:37 +0000

commit c758765e464e166b5495c76466facc79584bbe1e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2a587de219cc0765330fbf9fac6827bfaf29e29b)
---
 tools/xenstore/xenstored_control.c     | 31 +++++++-------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 29 +++++++------
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 118 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 1031a81c38..d0350c6ad8 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -155,7 +155,7 @@ bool lu_is_pending(void)
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 	/*
 	 * max_pars can be used to limit the size of the parameter vector,
@@ -167,7 +167,7 @@ struct cmd_s {
 	unsigned int max_pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -179,7 +179,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -281,7 +281,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -293,7 +293,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -306,7 +306,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 }
 
 #ifdef __MINIOS__
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	if (num)
@@ -318,7 +318,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 #else
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -333,7 +333,7 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -373,7 +373,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -875,7 +875,7 @@ static const char *lu_start(const void *ctx, struct connection *conn,
 	return NULL;
 }
 
-static int do_control_lu(void *ctx, struct connection *conn,
+static int do_control_lu(const void *ctx, struct connection *conn,
 			 char **vec, int num)
 {
 	const char *ret = NULL;
@@ -922,7 +922,7 @@ static int do_control_lu(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -961,7 +961,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd, len = 0;
@@ -997,7 +997,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	unsigned int cmd, num, off;
 	char **vec = NULL;
@@ -1017,11 +1018,11 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (cmds[cmd].max_pars)
 		num = min(num, cmds[cmd].max_pars);
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) < num)
 		return EIO;
 
-	return cmds[cmd].func(in, conn, vec + 1, num - 1);
+	return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index 98b6fbcea2..a8cb76559b 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,7 +16,8 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 void lu_read_state(void);
 
 struct connection *lu_get_connection(void);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 16504de420..411cc0e447 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1248,11 +1248,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1261,7 +1263,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1273,7 +1275,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1300,7 +1303,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1316,11 +1319,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1510,7 +1515,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1524,12 +1530,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1540,18 +1546,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1561,10 +1568,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 			return errno;
 		if (!name)
 			return ENOMEM;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1662,24 +1669,25 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
 			if (!name)
 				return ENOMEM;
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1694,7 +1702,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1704,13 +1712,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1723,7 +1733,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1740,7 +1751,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1755,7 +1766,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1790,7 +1801,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1798,7 +1809,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1874,6 +1886,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	/* At least send_error() and send_reply() expects conn->in == in */
 	assert(conn->in == in);
@@ -1898,10 +1911,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index e7c6886ccf..fb732d0a14 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -330,7 +330,7 @@ bool domain_is_unprivileged(struct connection *conn)
 	       domid_is_unprivileged(conn->domain->domid);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -534,7 +534,8 @@ static struct domain *introduce_domain(const void *ctx,
 }
 
 /* domid, gfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -552,7 +553,7 @@ int do_introduce(struct connection *conn, struct buffered_data *in)
 	if (port <= 0)
 		return EINVAL;
 
-	domain = introduce_domain(in, domid, port, false);
+	domain = introduce_domain(ctx, domid, port, false);
 	if (!domain)
 		return errno;
 
@@ -575,7 +576,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -619,7 +621,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -634,7 +637,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -649,7 +653,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -657,18 +662,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -689,7 +693,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 904faa923a..b9e1528901 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -24,25 +24,32 @@ void handle_event(void);
 void check_domains(void);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(int evtfd);
 void dom0_init(void);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 28774813de..3e3eb47326 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -481,7 +481,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -494,8 +495,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -544,7 +545,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -562,8 +564,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	if (!conn->transaction_started)
 		conn->ta_start_time = 0;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 85362bcce3..316c08b7f7 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -243,7 +243,7 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	return NULL;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -252,7 +252,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	errno = check_watch_path(conn, in, &(vec[0]), &relative);
+	errno = check_watch_path(conn, ctx, &(vec[0]), &relative);
 	if (errno)
 		return errno;
 
@@ -283,7 +283,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -291,7 +292,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 0e693f0839..091890edca 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:59:49 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:59:49 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434761.687212 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsk1-0000lU-PZ; Tue, 01 Nov 2022 14:59:49 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434761.687212; Tue, 01 Nov 2022 14:59:49 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsk1-0000lL-MA; Tue, 01 Nov 2022 14:59:49 +0000
Received: by outflank-mailman (input) for mailman id 434761;
 Tue, 01 Nov 2022 14:59:48 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsk0-0000l2-3A
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:48 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsk0-0000ZX-2V
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:48 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsk0-0001C5-1s
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:48 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Twgr/CAhOWWIphTqn4LULTWWDALvIvS4dYWcue3JTuY=; b=GZ/TQIL9ctkfn+KqpL765+J75t
	c6iI9KYbTBI/dbcuP5lbvUS/t/wu/BAk0XnkUg5NwpINfFlFbUEKwGri7od8KFbepSyMPSEVuDq2+
	7AsN5NYLVv5eGnwNVSc0onZX/TSuHLD6hCnoKo7AD9VBflNIUUzatqL1c2OX5iAmFnsk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: fix checking node permissions
Message-Id: <E1opsk0-0001C5-1s@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:59:48 +0000

commit 036fa8717b316a10b67ea8cf4d5dd200ac2b29af
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ab128218225d3542596ca3a02aee80d55494bef8)
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 411cc0e447..c676ee4e4e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1757,6 +1757,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index fb732d0a14..e2f1b09c60 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -875,7 +875,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -883,20 +882,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -909,8 +926,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -927,8 +942,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index b9e1528901..40fe5f6909 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -62,6 +62,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 14:59:58 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 14:59:58 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434762.687215 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opskA-0000ob-QV; Tue, 01 Nov 2022 14:59:58 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434762.687215; Tue, 01 Nov 2022 14:59:58 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opskA-0000oR-No; Tue, 01 Nov 2022 14:59:58 +0000
Received: by outflank-mailman (input) for mailman id 434762;
 Tue, 01 Nov 2022 14:59:58 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskA-0000oJ-6L
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:58 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskA-0000Zb-5f
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:58 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskA-0001CX-4s
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 14:59:58 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Sosa15PW0qv5ipX3b8YVdPfnmIh95XfwAwwtA+ljK9Q=; b=n7hPPfcwOiBj/IuD8lsFj19YvY
	GHO6ixrG8q3IRiQkZpM4kNjC0BsfVgDlFDMDNYqK5yPaoNVh11oNkYlSc6lpZomHeDsJPD5mRvN3H
	vL776V9J1swbJrsUZPA7LSqUQsfJMnsz/1YPN+iJez3tGsd2uTHwaNPnWOl2R7Vdo5lE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1opskA-0001CX-4s@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 14:59:58 +0000

commit 074b32e47174a30bb751f2e2c07628eb56117eb8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 86 ++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 31 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c676ee4e4e..3907c35643 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1377,45 +1377,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name)
 static struct node *construct_node(struct connection *conn, const void *ctx,
 				   const char *name)
 {
-	struct node *parent, *node;
-	char *parentname = get_parent(ctx, name);
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
 
 	if (!parentname)
 		return NULL;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
 
-	/* Add child to parent. */
-	if (add_child(ctx, parent, name))
-		goto nomem;
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
 
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
 
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:00:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:00:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434763.687219 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opskK-0001hP-T9; Tue, 01 Nov 2022 15:00:08 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434763.687219; Tue, 01 Nov 2022 15:00:08 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opskK-0001hG-PP; Tue, 01 Nov 2022 15:00:08 +0000
Received: by outflank-mailman (input) for mailman id 434763;
 Tue, 01 Nov 2022 15:00:08 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskK-0001cf-Ar
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:08 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskK-0000bz-8k
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:08 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskK-0001ED-8B
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:08 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=e9/XfzuO8P0hfXyXfQvNqo/T1O7VGhtshqIBWRoSOTQ=; b=Lue/S5qiy4M/KIq04MULRTSAhh
	qbDZ48ADZI0WPOoh1Uaf3skq4DQr7HIctgwQNP8eGwBFujSu8rF5z9oxhi9pF6VhGK4+P0xl+HFSU
	5Qf4K666p+f9fgO14F9Xo8CV8k/fHUm9veLW21om45APTmrSpvBnImNx+44wCXaarQ/I=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1opskK-0001ED-8B@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:00:08 +0000

commit 32ff913afed898e6aef61626a58dc0bf5c6309ef
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4)
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 3907c35643..f433a45dc2 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1608,15 +1608,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1626,7 +1626,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2325,6 +2327,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2377,12 +2390,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2399,11 +2407,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:00:20 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:00:20 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434764.687223 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opskU-0001k5-UM; Tue, 01 Nov 2022 15:00:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434764.687223; Tue, 01 Nov 2022 15:00:18 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opskU-0001jt-R4; Tue, 01 Nov 2022 15:00:18 +0000
Received: by outflank-mailman (input) for mailman id 434764;
 Tue, 01 Nov 2022 15:00:18 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskU-0001ji-CX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:18 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskU-0000cE-Bv
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:18 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opskU-0001FR-BA
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:18 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=a47rFhsCAgOds0G19xOE/qEsFgjiibTvvWOzDIPBnmI=; b=iRx/jaSHSFzmmpmQcGd4Y71fc9
	sEz032YIjZvlry/+TPA+LyDcHe88YkILdPsqwEFb20rAimogZ1N6YdIUL9ksskcE12IREUYi0O/xN
	0qzSGkC3pUQn79CN94o3WrDHZsZpnGqY4SXvIP6qEUcWh++M/7IewsOSqoiyELbLajFo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: add generic treewalk function
Message-Id: <E1opskU-0001FR-BA@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:00:18 +0000

commit 01ab4910229696e51c59a80eb86d0fedeeccb54b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d7c5d19bc27492360196e7dad2b227908564fff)
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f433a45dc2..2cda3ee375 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1838,6 +1838,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2305,18 +2434,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2376,7 +2493,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index bfd3fc1e9d..2d9942171d 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -202,6 +202,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -338,6 +339,45 @@ void read_state_buffered_data(const void *ctx, struct connection *conn,
 			      const struct xs_state_connection *sc);
 void read_state_node(const void *ctx, const void *state);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:00:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:00:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434765.687227 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opske-0001mo-VI; Tue, 01 Nov 2022 15:00:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434765.687227; Tue, 01 Nov 2022 15:00:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opske-0001mh-Sf; Tue, 01 Nov 2022 15:00:28 +0000
Received: by outflank-mailman (input) for mailman id 434765;
 Tue, 01 Nov 2022 15:00:28 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opske-0001mZ-HX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:28 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opske-0000cO-Gr
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:28 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opske-0001GG-ES
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:28 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Xx4fAn25fk92Uq13jCcVNxvHNWuOGmK0m59irIo2jQg=; b=RhPiO9k4W0R+oRjVWwr1p6yyKL
	TWfK6+TmD1ESR06QmnU16dUf13BHVLAozapmjElOw3GC94e6TJ6WlOv5pjV1VTH+/iAF1hYMLq3gj
	KQQQE1lmOw9wnJ2+wZeEP3eNJW/LijiFH7og9Ffr8K0Q51sHVyWRkXY/6pCWd15NfYV4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: simplify check_store()
Message-Id: <E1opske-0001GG-ES@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:00:28 +0000

commit c5a76df793c638423e1388528dc679a3e020a477
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 70f719f52a220bc5bc987e4dd28e14a7039a176b)
---
 tools/xenstore/xenstored_core.c | 47 +++++++++++++----------------------------
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2cda3ee375..760f3c16c7 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2477,50 +2477,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-		if (!children) {
-			log("check_store create table: ENOMEM");
-			return ENOMEM;
-		}
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2530,19 +2514,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:00:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:00:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434766.687231 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opskp-0001qI-2B; Tue, 01 Nov 2022 15:00:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434766.687231; Tue, 01 Nov 2022 15:00:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsko-0001qA-Vj; Tue, 01 Nov 2022 15:00:38 +0000
Received: by outflank-mailman (input) for mailman id 434766;
 Tue, 01 Nov 2022 15:00:38 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsko-0001q1-KN
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:38 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsko-0000ck-Jg
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:38 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsko-0001HN-JA
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:38 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=twluQFpdtEwixreWFIpkAhU0WwvUAiusQHWi9o/CESs=; b=picWhJYYgncfawlVSZIIl+myVh
	2szLLE4K/xeVfHtew6/VE5MvNj07IrS5j6PyZVGet11WFEtmr0PT8Lql/TPTZgUyCjxHYWmMZFvd+
	wI9OYnGHgM75tdHy3sQIr9mgynvS/7Qm6r8r06CRevW24eSJFsWPjKF7g5EPKqbdpL64=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: use treewalk for check_store()
Message-Id: <E1opsko-0001HN-JA@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:00:38 +0000

commit f5a4c26b2efc55a5267840fcb31f95c00cc25d10
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 760f3c16c7..efdd1888fd 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2444,18 +2444,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2469,70 +2457,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
+	struct hashtable *reachable = arg;
 
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
-
-			childnode = read_node(NULL, childname, childname);
-
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2581,24 +2528,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char * root = talloc_strdup(NULL, "/");
-	struct hashtable * reachable =
-		create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
+
+	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
 		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:00:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:00:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434767.687237 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsl0-0001t8-4U; Tue, 01 Nov 2022 15:00:50 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434767.687237; Tue, 01 Nov 2022 15:00:50 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsl0-0001sw-13; Tue, 01 Nov 2022 15:00:50 +0000
Received: by outflank-mailman (input) for mailman id 434767;
 Tue, 01 Nov 2022 15:00:48 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsky-0001sn-NN
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:48 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsky-0000co-Mi
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:48 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsky-0001IU-Lx
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:48 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=qXF2JC6kgk6vgcGOTxairqvS17DSfbSzYj3f6qTzfhc=; b=Xm1cV4zG38e6sCvegF/MuT7l4s
	3nktq5Z4QEBaFEQdp+BoKPFRnsXW9uNThSOCTgUPAUGQDh2H7t2THDFfvAJkUX5KXPh+vL/nHk01T
	lP57oG+ZAn2veHM5sjgp7GrGRlbrRx6Hc1NDoeVMIVQogrxCAlRJAKtpWCdub402Xv6E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1opsky-0001IU-Lx@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:00:48 +0000

commit 1514de3a5f23aef451133367d8dc04a26b88052f
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ea16962053a6849a6e7cada549ba7f8c586d85c6)
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index efdd1888fd..58fb651542 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1334,21 +1334,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1619,69 +1604,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1689,9 +1664,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1728,7 +1715,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:01:00 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:01:00 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434768.687239 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opslA-0001vu-5K; Tue, 01 Nov 2022 15:01:00 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434768.687239; Tue, 01 Nov 2022 15:01:00 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opslA-0001vm-2c; Tue, 01 Nov 2022 15:01:00 +0000
Received: by outflank-mailman (input) for mailman id 434768;
 Tue, 01 Nov 2022 15:00:58 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsl8-0001va-Qb
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:58 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsl8-0000cy-Pw
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:58 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsl8-0001K9-PM
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:00:58 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=/CAJsegI7WN4XCKJFAaMajWZHh1S8zanlO8zCtYjkfs=; b=SO5Ue2JI5wxq28GPvOeUGf5Vl6
	u85fP0mvmRcnguWQQU+BpIgs3xpYJwtCcHA2AVqtXC1/088iJfpfCKeYMw7S7vPwxqzUACULWVtpg
	15yZsmr8yYgKQXu8IUYWmeULmi+EqFWNj757TveybZg4PTBBVuXoW5Hda3uIj2gz8jeQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: use treewalk for creating node records
Message-Id: <E1opsl8-0001K9-PM@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:00:58 +0000

commit 7682de61a49f7692cbd31a62f12c0ca12e069575
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: use treewalk for creating node records
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when creating the node records during a live update.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 297ac246a5d8ed656b349641288f3402dcc0251e)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++++++-------------------------
 1 file changed, 40 insertions(+), 65 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 58fb651542..05d349778b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -3120,101 +3120,76 @@ const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
 	return NULL;
 }
 
-static const char *dump_state_node_tree(FILE *fp, char *path,
-					unsigned int path_max_len)
+struct dump_node_data {
+	FILE *fp;
+	const char *err;
+};
+
+static int dump_state_node_err(struct dump_node_data *data, const char *err)
 {
-	unsigned int pathlen, childlen, p = 0;
+	data->err = err;
+	return WALK_TREE_ERROR_STOP;
+}
+
+static int dump_state_node(const void *ctx, struct connection *conn,
+			   struct node *node, void *arg)
+{
+	struct dump_node_data *data = arg;
+	FILE *fp = data->fp;
+	unsigned int pathlen;
 	struct xs_state_record_header head;
 	struct xs_state_node sn;
-	TDB_DATA key, data;
-	const struct xs_tdb_record_hdr *hdr;
-	const char *child;
 	const char *ret;
 
-	pathlen = strlen(path) + 1;
-
-	set_tdb_key(path, &key);
-	data = tdb_fetch(tdb_ctx, key);
-	if (data.dptr == NULL)
-		return "Error reading node";
-
-	/* Clean up in case of failure. */
-	talloc_steal(path, data.dptr);
-
-	hdr = (void *)data.dptr;
+	pathlen = strlen(node->name) + 1;
 
 	head.type = XS_STATE_TYPE_NODE;
 	head.length = sizeof(sn);
 	sn.conn_id = 0;
 	sn.ta_id = 0;
 	sn.ta_access = 0;
-	sn.perm_n = hdr->num_perms;
+	sn.perm_n = node->perms.num;
 	sn.path_len = pathlen;
-	sn.data_len = hdr->datalen;
-	head.length += hdr->num_perms * sizeof(*sn.perms);
+	sn.data_len = node->datalen;
+	head.length += node->perms.num * sizeof(*sn.perms);
 	head.length += pathlen;
-	head.length += hdr->datalen;
+	head.length += node->datalen;
 	head.length = ROUNDUP(head.length, 3);
 
 	if (fwrite(&head, sizeof(head), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node head error");
 	if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node state error");
 
-	ret = dump_state_node_perms(fp, hdr->perms, hdr->num_perms);
+	ret = dump_state_node_perms(fp, node->perms.p, node->perms.num);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
+
+	if (fwrite(node->name, pathlen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node path error");
 
-	if (fwrite(path, pathlen, 1, fp) != 1)
-		return "Dump node path error";
-	if (hdr->datalen &&
-	    fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1)
-		return "Dump node data error";
+	if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node data error");
 
 	ret = dump_state_align(fp);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
 
-	child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen;
-
-	/*
-	 * Use path for constructing children paths.
-	 * As we don't write out nodes without having written their parent
-	 * already we will never clobber a part of the path we'll need later.
-	 */
-	pathlen--;
-	if (path[pathlen - 1] != '/') {
-		path[pathlen] = '/';
-		pathlen++;
-	}
-	while (p < hdr->childlen) {
-		childlen = strlen(child) + 1;
-		if (pathlen + childlen > path_max_len)
-			return "Dump node path length error";
-		strcpy(path + pathlen, child);
-		ret = dump_state_node_tree(fp, path, path_max_len);
-		if (ret)
-			return ret;
-		p += childlen;
-		child += childlen;
-	}
-
-	talloc_free(data.dptr);
-
-	return NULL;
+	return WALK_TREE_OK;
 }
 
 const char *dump_state_nodes(FILE *fp, const void *ctx)
 {
-	char *path;
-
-	path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX + 1);
-	if (!path)
-		return "Path buffer allocation error";
+	struct dump_node_data data = {
+		.fp = fp,
+		.err = "Dump node walk error"
+	};
+	struct walk_funcs walkfuncs = { .enter = dump_state_node };
 
-	strcpy(path, "/");
+	if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data))
+		return data.err;
 
-	return dump_state_node_tree(fp, path, XENSTORE_ABS_PATH_MAX + 1);
+	return NULL;
 }
 
 void read_state_global(const void *ctx, const void *state)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:01:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:01:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434769.687243 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opslK-0001ya-72; Tue, 01 Nov 2022 15:01:10 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434769.687243; Tue, 01 Nov 2022 15:01:10 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opslK-0001yQ-4B; Tue, 01 Nov 2022 15:01:10 +0000
Received: by outflank-mailman (input) for mailman id 434769;
 Tue, 01 Nov 2022 15:01:08 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslI-0001yC-Tn
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:08 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslI-0000dF-TB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:08 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslI-0001LK-SO
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:08 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=VnJkqHHJD0tpC1G86FxDK+m8XhIf8/UJtKsBErRSlaU=; b=iSAUaiQwv8fyGbYjqNPI64VxfU
	eCx/X2dIl+WKSwWSy9t44HhpdAR+dcltLVBPihLz3sTVJJkkWQNwZRXgIUnZ648GGrcEIu6Fei5/f
	te64LuDSMJGGcTTfByxUsx+rnfuINlc3M2MDDKfDx4YBJceTLTYaJ9brVnysU0g4iepQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1opslI-0001LK-SO@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:01:08 +0000

commit 825332daeac9fc3ac1e482e805ac4a3bc1e1ab34
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 755d3f9debf8879448211fffb018f556136f6a79)
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 84 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 80 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 05d349778b..0ca1a5a19a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -80,6 +80,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -757,7 +758,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -800,7 +801,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1651,7 +1652,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1715,7 +1716,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2639,6 +2640,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2663,6 +2666,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 #ifndef NO_LIVE_UPDATE
@@ -2742,7 +2746,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2778,6 +2782,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2d9942171d..725793257e 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -240,6 +240,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(bool live_update);
 struct connection *new_connection(const struct interface_funcs *funcs);
 struct connection *get_connection_by_id(unsigned int conn_id);
@@ -286,6 +289,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index e2f1b09c60..8b134017a2 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -227,10 +227,64 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		set_tdb_key(node->name, &key);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -851,15 +905,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -920,23 +974,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -954,15 +996,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1081,7 +1123,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 40fe5f6909..5454e925ad 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -61,7 +61,7 @@ const char *get_implicit_path(const struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:01:20 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:01:20 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434770.687247 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opslU-00021v-9z; Tue, 01 Nov 2022 15:01:20 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434770.687247; Tue, 01 Nov 2022 15:01:20 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opslU-00021n-79; Tue, 01 Nov 2022 15:01:20 +0000
Received: by outflank-mailman (input) for mailman id 434770;
 Tue, 01 Nov 2022 15:01:19 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslT-00021d-0p
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:19 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslT-0000dS-04
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:19 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslS-0001M7-Va
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:18 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=zibLE+hd9qaG9iOSr9bg7BQXvnxyVjWSo8LxS3ni5yY=; b=MiDEZJvQtwdDhuV3qTDO9BrXv7
	GawqMDCaP58tvVgbImic/yaRt6zT/my+rLegS9jXHvK0lCG9BWUDiuuU7uO//TCyKq6PLfgHp88JY
	9heWjQIBKbgDx9y0Klec8NryP5tOv0NasLIdobJK0E+KRMWg2Pu8lFiyugHJhFAAkeiI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: make the internal memory data base the default
Message-Id: <E1opslS-0001M7-Va@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:01:18 +0000

commit 8b81fc185ab13feca2f63eda3792189e5ac11a97
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d174fefa90487ddd25ebc618028f67b2e8a1f795)
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 11ebf79e6d..8d1d1a4f1e 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -223,9 +223,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom->guest_domid = domid;
     dom->cmdline = xc_dom_strdup(dom, cmdline);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 0ca1a5a19a..041124d8b7 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2329,7 +2329,7 @@ static void accept_connection(int sock)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2639,7 +2639,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2665,7 +2666,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2746,7 +2747,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2780,7 +2782,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:01:30 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:01:30 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434771.687251 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsle-00024x-BW; Tue, 01 Nov 2022 15:01:30 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434771.687251; Tue, 01 Nov 2022 15:01:30 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsle-00024p-8e; Tue, 01 Nov 2022 15:01:30 +0000
Received: by outflank-mailman (input) for mailman id 434771;
 Tue, 01 Nov 2022 15:01:29 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsld-00024Z-3i
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:29 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsld-0000dW-2v
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:29 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsld-0001Mw-2H
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:29 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Ut8TChiYRXMlTEeKPzmayDRElMMJxdcGI/5Dmxicf9g=; b=BzcUsujsF3KO98X4iuIMgxF18V
	kPtFlTCmBQwHezBJgnQCCTkiOzm5M+/oLysz2VuPrkxXRUKywdwsKKTTwwk2BdKbjYqvY1YhMrHGR
	mgIbQJic9a2cTBOCYDqFUgTFHC14cKoT1Z1atgs9mMmdPvegD1m/3keqcpSo47dYD3cI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] docs: enhance xenstore.txt with permissions description
Message-Id: <E1opsld-0001Mw-2H@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:01:29 +0000

commit 1f5b394d6ed0ee26b5878bd0cdf4a698bbc4294f
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d084d2c6dff7044956ebdf83a259ad6081a1d921)
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index a7d006519a..eccd596ee3 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:01:40 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:01:40 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434772.687255 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opslo-000277-D7; Tue, 01 Nov 2022 15:01:40 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434772.687255; Tue, 01 Nov 2022 15:01:40 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opslo-00026z-AH; Tue, 01 Nov 2022 15:01:40 +0000
Received: by outflank-mailman (input) for mailman id 434772;
 Tue, 01 Nov 2022 15:01:39 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsln-00026l-6k
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:39 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsln-0000fW-62
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:39 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsln-0001Nj-5B
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:39 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sLJkkN/n02GyL8qBCgZB+Qa33sVtdFjdP6nysM766VE=; b=TV0j3QM23XTD3MqB6Q1r5+d2R/
	dLcQgxuqVwk8uc/wCxLIq4WwZZfymqcvE9JqI6Oe9ftfbF852yjYdHUWmEPX9sTDp0cx+G/v5UCtR
	H9lnpawBdb+ry6cyxp2KnWW/dKQfxz+ZFVeLgVagTqqtN2T5dcIbwVzl6lOdJVeX1/eY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1opsln-0001Nj-5B@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:01:39 +0000

commit 5b0919f2c0e5060f6e0bc328f100abae0a9f07b8
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit db471408edd46af403b8bd44d180a928ad7fbb80)
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 20e67b1427..70f0c83de4 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -87,10 +87,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; SymbolMap.iter (fun _ -> recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid _ node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = SymbolMap.map walk node.children }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			SymbolMap.map walk node.children |> SymbolMap.filter is_valid } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -444,11 +455,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:01:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:01:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434773.687259 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsly-0002Aa-Eg; Tue, 01 Nov 2022 15:01:50 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434773.687259; Tue, 01 Nov 2022 15:01:50 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsly-0002AS-Bo; Tue, 01 Nov 2022 15:01:50 +0000
Received: by outflank-mailman (input) for mailman id 434773;
 Tue, 01 Nov 2022 15:01:49 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslx-0002A4-9X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:49 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslx-0000fc-8t
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:49 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opslx-0001On-8H
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:49 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=YPK7Qk0EMKCEZBvro1D0T8IaQbAS6O74qfaT+1hc3vo=; b=LmlN9uZZs8BkES7ufi98PuFpgj
	husFVl6depj5LhHmyWsKphakoH1RgFVJ1F+u3nJfc/8WXyoVbH8ZfImTomoA/qEmi0hcpnzE42j1C
	Yuzxo+Nge1IikKvU4XM5MfiLcrVJX/PXiA20vrSPdCDf/EUu9wD7nwXB60IaT7RI563E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1opslx-0001On-8H@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:01:49 +0000

commit 635390415f4a9c0621330f0b40f8c7e914c4523f
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3)
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index ce39ce28b5..6cb990ee7f 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -722,7 +722,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:02:00 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:02:00 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434774.687262 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsm8-0002DE-Fo; Tue, 01 Nov 2022 15:02:00 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434774.687262; Tue, 01 Nov 2022 15:02:00 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsm8-0002D7-DF; Tue, 01 Nov 2022 15:02:00 +0000
Received: by outflank-mailman (input) for mailman id 434774;
 Tue, 01 Nov 2022 15:01:59 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsm7-0002Cw-CV
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:59 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsm7-0000fg-Br
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:59 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsm7-0001Pc-BB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:01:59 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=HxkZuFrpTbvIqW4GgSEClyOn1P1EClOhNP5URBILDpc=; b=HoWJ/LTbQPsZGKKOnpyTM7cw73
	B7pk7Hhju/BylwdLSLvoAh3qIkYOrm6tccojZLm0gubvPLzNN5ODxrvCTX5hD5BzMnt9tPSo3eNj9
	RTQe/J1CUHMALxPpOAjvkmyEcDeMlLNFit6os9OacXB+LCw3pJ40Ns5tEWo9Qgre+2+s=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: fix deleting node in transaction
Message-Id: <E1opsm7-0001Pc-BB@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:01:59 +0000

commit 4305807dfdc183f4acd170fe00eb66b338fa6430
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187)
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 3e3eb47326..7ffe21bb52 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -418,7 +418,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:02:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:02:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434775.687267 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsmI-0002HZ-IM; Tue, 01 Nov 2022 15:02:10 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434775.687267; Tue, 01 Nov 2022 15:02:10 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opsmI-0002HS-En; Tue, 01 Nov 2022 15:02:10 +0000
Received: by outflank-mailman (input) for mailman id 434775;
 Tue, 01 Nov 2022 15:02:09 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsmH-0002HJ-Fc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:02:09 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsmH-0000fx-Er
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:02:09 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opsmH-0001QY-EG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:02:09 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=XWW1hakXMU1CKo4quFpNlIbn0FGvBK//0LKiMKhOUn4=; b=zuSEi5YOJI9OHB31PqWD4gH2Ze
	gOEMZRkNEDzNPHgAGQ9uCD/WKC1DAFB5f3TMwK75gwU8WdK3/9/zMCbTZ8gBsPnbSMspWhCedVbVw
	NBlrfJq5T9zs05poMhgFFqLe21qhEmcwSSlHR0wj7AiAzmx2p3eUW5j0vz+BDGKerQNg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.16] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1opsmH-0001QY-EG@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:02:09 +0000

commit 1bdd7c438b399e2ecce9e3c72bd7c1ae56df60f8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff)
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 041124d8b7..ccb7f0a925 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -727,8 +727,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -846,10 +845,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 unsigned int perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 7ffe21bb52..ac854197ca 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -199,25 +200,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -240,7 +236,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -259,10 +254,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -273,9 +264,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -302,7 +294,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -321,7 +313,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -333,7 +325,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -371,100 +362,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -556,6 +537,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -579,13 +561,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -660,7 +646,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -672,11 +658,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:22:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:22:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434785.687282 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt5b-0005I8-7k; Tue, 01 Nov 2022 15:22:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434785.687282; Tue, 01 Nov 2022 15:22:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt5b-0005I0-5A; Tue, 01 Nov 2022 15:22:07 +0000
Received: by outflank-mailman (input) for mailman id 434785;
 Tue, 01 Nov 2022 15:22:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5Z-0005Hu-Ua
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5Z-00014d-PB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5Z-0002XA-LS
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=WH3ESwRLcz78pfnTujWhEk5GM0iDtmdgTzVc9SGEzK8=; b=zJY8rN6EvQ/dp+e8EDCllsYcrm
	60myJaUj7boxXUjPc2lNFWMyky80YVl54ZiuiI1SEfEdbZOe2/0P8WCVd0JW1OjzCKPdRYb49LV3h
	wJBgqLYrVsQASSgw8D/sE2rwUIWpqPZrQ7VzcuPrrY6zMy0XxRZtvhZucbBNC3Dw8ULc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1opt5Z-0002XA-LS@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:22:05 +0000

commit ee03d9b56e6141422b4ef2444f93cf2e88e6a26c
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 1cd3cc7ea27cda7640a8d895e09617b61c265697)
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9172dd7671..a00c49e404 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1054,9 +1054,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -1065,7 +1064,7 @@ static int destroy_node(void *_node)
 	set_tdb_key(node->name, &key);
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -1074,7 +1073,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1096,23 +1096,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:22:17 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:22:17 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434786.687286 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt5l-0005K0-9K; Tue, 01 Nov 2022 15:22:17 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434786.687286; Tue, 01 Nov 2022 15:22:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt5l-0005Js-6g; Tue, 01 Nov 2022 15:22:17 +0000
Received: by outflank-mailman (input) for mailman id 434786;
 Tue, 01 Nov 2022 15:22:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5j-0005Je-TO
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5j-00014n-Sb
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5j-0002XZ-Rb
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Gmy1n3g6SzoI7XMeFuL/jcwEOMSpB3Shaw2eepewXtI=; b=oK7IyBC5NsIj7Y0GuszThJpEvq
	o2slV8DJPjEVOXK3oQs8Mp1hZOw93Ub1A2mUKDO/nJoPkLfZMhBrzOn1RMjMMVjITFl0YvrRpUgFv
	TEcgeKFtQztXIfxPix4ozFF+r8bMKnJ3ptPqco4ErksG8oXAtMWSzt1hvxbB9qc1ZlPY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1opt5j-0002XZ-Rb@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:22:15 +0000

commit 579e7334b909c22efc65c5df22e8afe414882154
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34)
---
 tools/xenstore/xenstored_core.c        | 23 +++++++++++++++--------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index a00c49e404..b28c2c66b5 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -531,15 +531,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
@@ -1056,16 +1058,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	set_tdb_key(node->name, &key);
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 0c9a0961b5..900336afa4 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -148,6 +148,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd07fb0f21..faf6c930e4 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:22:27 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:22:27 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434787.687290 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt5v-0005Mi-Ak; Tue, 01 Nov 2022 15:22:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434787.687290; Tue, 01 Nov 2022 15:22:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt5v-0005Ma-8B; Tue, 01 Nov 2022 15:22:27 +0000
Received: by outflank-mailman (input) for mailman id 434787;
 Tue, 01 Nov 2022 15:22:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5u-0005MR-0U
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5t-000151-W0
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt5t-0002Y0-V4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=D6vaQowkjsfbBau4I87MCFuDj8F5UmUPX52xxno/Nw0=; b=NC2KZGRFcrnU+JxyH6TCq+2K8k
	PxYJs5ggYZ53cZXyuPqv0f0UKLfAdjPs03DbX9sFJiPdsuGxwpUtrI7ArmlwhQzila9XQZIZHWgLf
	3HkJaPm09Q5MqgewmnuooUx524HPpNn2siFd+apTIa+WjTTh4w7Tevfk4HRNT2Poqs4A=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: split up send_reply()
Message-Id: <E1opt5t-0002Y0-V4@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:22:25 +0000

commit 0d8bea403d4d1763dddb0c1c81d30efebafb6962
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32)
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 39 ++++-----------------
 3 files changed, 52 insertions(+), 62 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b28c2c66b5..01d4a2e440 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -733,49 +733,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -783,8 +766,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 900336afa4..38d97fa081 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -180,6 +180,7 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index db89e0141f..a116f967dc 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -85,35 +85,6 @@ static const char *get_watch_path(const struct watch *watch, const char *name)
 	return path;
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
-{
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
-
-	name = get_watch_path(watch, name);
-
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
-}
-
 /*
  * Check permissions of a specific watch to fire:
  * Either the node itself or its parent have to be readable by the connection
@@ -190,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -292,7 +267,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:22:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:22:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434788.687294 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt65-0005PG-CL; Tue, 01 Nov 2022 15:22:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434788.687294; Tue, 01 Nov 2022 15:22:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt65-0005P8-9k; Tue, 01 Nov 2022 15:22:37 +0000
Received: by outflank-mailman (input) for mailman id 434788;
 Tue, 01 Nov 2022 15:22:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt64-0005Ow-3x
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt64-00015W-3E
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt64-0002Yl-2G
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=eSyTK57XKAbVWudo2tIuYUXE/og2u23O1gHaWj1/g3k=; b=0LLRTBIS8tCAOQIN48HqZWKh7o
	a+45qh298HAwdnFkpIKpcTzo5BhZpIGScEqpGMA7M95p/atQAwo1lJJTM6ZOSRbSdH9FFAzOfBnzK
	NzD5GXI8yblXy3uxXzrXNnPaYv/61O6N+Jzy3hN6OEMCHYaMULwZprXg0xqwGK4ZZ7Wk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1opt64-0002Yl-2G@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:22:36 +0000

commit b322923894ea23f397efc58a938cb9213d7dc617
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ead062a68a9c201a95488e84750a70a107f7b317)
---
 tools/xenstore/xenstored_core.c   | 26 +++++++++++++++++---------
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c |  7 +------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 01d4a2e440..6498bf6036 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -211,6 +211,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -254,8 +269,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
@@ -1472,18 +1486,12 @@ static struct {
  */
 static void ignore_connection(struct connection *conn)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored\n", conn);
 
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 38d97fa081..0ba5b783d4 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -270,6 +270,8 @@ int remember_string(struct hashtable *hash, const char *str);
 
 void set_tdb_key(const char *name, TDB_DATA *key);
 
+void conn_free_buffered_data(struct connection *conn);
+
 const char *dump_state_global(FILE *fp);
 const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 				     const struct connection *conn,
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3d4d0649a2..72a5cd3b9a 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -417,15 +417,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:22:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:22:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434789.687299 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6F-0005Rm-FE; Tue, 01 Nov 2022 15:22:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434789.687299; Tue, 01 Nov 2022 15:22:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6F-0005Re-BE; Tue, 01 Nov 2022 15:22:47 +0000
Received: by outflank-mailman (input) for mailman id 434789;
 Tue, 01 Nov 2022 15:22:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6E-0005RS-7b
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6E-00015g-6s
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6E-0002Zy-5a
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=2M++bTVFeR85RhAvBIgZ8kvpjYtomBulGb7dvsydYTg=; b=Yyxu3S5ej4p+MTB/rzd26XFDGs
	ea9SCCu/wtqPJo32lIN9c80okJFj1mQmK15Xll2EhJtTDqLZVs2ykKUZq+PtRQ2PFkTzJS20wYJoR
	9HzKw8FwGYxGsLfz9i7pdELn0CSvpZHEZbNvLk/grVP5SW3FKzzHKbgK+Tvjm2ycBdVs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: reduce number of watch events
Message-Id: <E1opt6E-0002Zy-5a@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:22:46 +0000

commit 8999db805e5ef55172a85d67695429edc3d78771
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297)
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 6498bf6036..5157a7527f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1261,7 +1261,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1273,7 +1273,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1285,7 +1285,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1311,13 +1316,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index faf6c930e4..54432907fc 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -323,6 +327,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index a116f967dc..bc6d833028 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:22:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:22:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434790.687302 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6P-0005V8-HI; Tue, 01 Nov 2022 15:22:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434790.687302; Tue, 01 Nov 2022 15:22:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6P-0005V0-E5; Tue, 01 Nov 2022 15:22:57 +0000
Received: by outflank-mailman (input) for mailman id 434790;
 Tue, 01 Nov 2022 15:22:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6O-0005Us-Ao
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6O-00015q-A7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6O-0002ad-9F
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:22:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=bpBtc9azParMNNnzuWwdL7H2yADR9mpcrjBsPdQA6p8=; b=txPKd3aGF2PnkwaBoFUK9MwWmx
	KMEFO/evz7o9KmGVt+561vxRzIh+836P6kWSG3KsQPKtwnGRgk5dxaCruLVuMo+ibe++as3lNJU+R
	bO5DCdig3ee1e6NgOBWnrGp0ejEcuMVp6LpsqdBn2SCyRH5UA2Xv7FqosLJYtyTeu3UQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: let unread watch events time out
Message-Id: <E1opt6O-0002ad-9F@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:22:56 +0000

commit 53a77b82717530d836300f1de0ad037de85477dd
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 5285dcb1a5c01695c11e6397c95d906b5e765c98)
---
 tools/xenstore/xenstored_core.c | 133 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5157a7527f..ee3396fefa 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -108,6 +108,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -211,19 +213,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -382,6 +457,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -402,10 +478,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (domain_can_read(conn) ||
 			    (domain_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -760,6 +838,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -811,6 +890,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -2099,6 +2184,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2121,6 +2209,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2135,6 +2224,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2149,7 +2271,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:U", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2198,6 +2320,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
@@ -2642,6 +2767,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 		barf("error restoring buffered data");
 
 	memcpy(bdata->buffer, data, len);
+	if (bdata->hdr.msg.type == XS_WATCH_EVENT && timeout_watch_event_msec &&
+	    domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 0ba5b783d4..2db577928f 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <dirent.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -67,6 +68,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -110,6 +113,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -237,6 +241,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:23:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:23:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434791.687306 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6a-0005Xq-IY; Tue, 01 Nov 2022 15:23:08 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434791.687306; Tue, 01 Nov 2022 15:23:08 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6a-0005Xi-Fs; Tue, 01 Nov 2022 15:23:08 +0000
Received: by outflank-mailman (input) for mailman id 434791;
 Tue, 01 Nov 2022 15:23:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6Y-0005XQ-ER
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:06 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6Y-00016G-Dg
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:06 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6Y-0002bT-Cl
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=1k6LyQSUGTsbKQ0Fe9lS/B9NgFoHTb1cBnTq8Gu1G3Y=; b=sl9aY6lXuyt0tpanYCCVwio4US
	/533ahDu9SwXLTYAApr/OORmFtQIhvJL8Muku9vTGxYHoIiiQ7XzYqDZjJqM3xYbkUTU7Zmv98bNz
	xNgvPO81WoRNSj14PxrZiNFdWF3AYRX10Sn0fR6mGI9AdzllPkligTDW/CD1Ee45Axb0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: limit outstanding requests
Message-Id: <E1opt6Y-0002bT-Cl@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:23:06 +0000

commit 56300e8e1781cee1b6a514e5f2bea234a7885d55
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 36de433a273f55d614c83b89c9a8972287a1e475)
---
 tools/xenstore/xenstored_core.c   | 88 +++++++++++++++++++++++++++++++++++++--
 tools/xenstore/xenstored_core.h   | 20 ++++++++-
 tools/xenstore/xenstored_domain.c | 38 ++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 +++++--
 5 files changed, 150 insertions(+), 14 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ee3396fefa..d871f217af 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -107,6 +107,7 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -223,12 +224,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -244,6 +257,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -399,6 +436,7 @@ int delay_request(struct connection *conn, struct buffered_data *in,
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -412,6 +450,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -859,6 +902,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -866,7 +911,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -896,8 +942,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1658,6 +1709,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1727,6 +1779,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
 	new->is_ignored = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 	INIT_LIST_HEAD(&new->delayed);
@@ -2184,6 +2237,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2209,6 +2265,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2257,6 +2314,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2271,8 +2342,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
-				  NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
 			no_domain_init = true;
@@ -2320,6 +2391,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
@@ -2776,6 +2850,14 @@ static void add_buffered_data(struct buffered_data *bdata,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	/*
+	 * Watch events are never "outstanding", but the request causing them
+	 * are instead kept "outstanding" until all watch events caused by that
+	 * request have been delivered.
+	 */
+	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
+		domain_outstanding_inc(conn);
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2db577928f..fcb27399f1 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -56,6 +56,8 @@ struct xs_state_connection;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -63,6 +65,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -115,6 +128,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -184,7 +200,8 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -240,6 +257,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 72a5cd3b9a..979f8c6298 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -78,6 +78,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -287,8 +290,12 @@ bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	if (conn->is_ignored)
 		return false;
@@ -337,7 +344,7 @@ static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -398,9 +405,6 @@ static int new_domain(struct domain *domain, int port, bool restore)
 	domain->conn->domain = domain;
 	domain->conn->id = domain->domid;
 
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
-
 	return 0;
 }
 
@@ -944,6 +948,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index dc97591713..5757a65571 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -68,6 +68,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index bc6d833028..1d664e3d6b 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -269,8 +272,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	trace_create(watch, "watch");
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:23:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:23:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434792.687310 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6k-0005ab-KK; Tue, 01 Nov 2022 15:23:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434792.687310; Tue, 01 Nov 2022 15:23:18 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6k-0005aS-HP; Tue, 01 Nov 2022 15:23:18 +0000
Received: by outflank-mailman (input) for mailman id 434792;
 Tue, 01 Nov 2022 15:23:16 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6i-0005aB-HY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:16 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6i-00016Q-Gu
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:16 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6i-0002cE-GB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:16 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=UV2Q1knWyNK6nqI3CKVwzQ0H67BaHzWDYYzZ4to5/Dg=; b=FZBjSrC6nvPXUjX6geObg3QiZ8
	RxfZT3rkf8biixQWqPa6gF35G9mdpFn9jK/DGoWdLcvxxMqz4sg3Wz8UZ9wBzp86NDhw9RfRx3wkT
	ZXu/gtsVYpqOSIOr6TnrHYb/Viy9L+zS7K9mbK54GQI2HLaPH1rIxWrPk/EN9mmIq9Rw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1opt6i-0002cE-GB@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:23:16 +0000

commit 97c251f953c58aec7620499ac12924054b7cd758
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2)
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index d871f217af..6ea06e20df 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -882,6 +882,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -914,7 +915,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -936,12 +937,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index fcb27399f1..afbd982c26 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -62,6 +62,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:23:27 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:23:27 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434793.687314 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6t-0005dn-Nk; Tue, 01 Nov 2022 15:23:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434793.687314; Tue, 01 Nov 2022 15:23:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt6t-0005df-Kz; Tue, 01 Nov 2022 15:23:27 +0000
Received: by outflank-mailman (input) for mailman id 434793;
 Tue, 01 Nov 2022 15:23:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6s-0005dU-KU
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6s-00016e-Ju
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:26 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt6s-0002cn-J9
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:26 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=E0uRV9Hyn7gP9U5x0zfyUUtNN1d3z1ISIrHn5cbFAmU=; b=Yiwo/vOvsjQMK6xrCyb5jwhONQ
	fN2VRjmJudG6s+rl1JYmgW3dmUahLJvQ176irxQmq8hphLKF6Ba/RhmZq/TttzUPHY30SBRy07WY3
	JLdqhSP2Gma3l5ax+EyWMgzFeN+7vSQqSTDQEhUBD2HTp7mHtlsB9qxYGc6YU8/ObaJU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: fix connection->id usage
Message-Id: <E1opt6s-0002cn-J9@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:23:26 +0000

commit 3e51699fcc578c7c005fd4add70cf7c8117d0af9
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831)
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 8e470f2b20..211fe1fd9b 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -821,7 +821,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	unsigned int cmd, num, off;
 	char **vec = NULL;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	off = get_string(in, 0);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index afbd982c26..c0a056ce13 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -118,7 +118,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this connection ignored? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 54432907fc..ee1b09031a 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -477,7 +477,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:23:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:23:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434795.687318 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt73-0005gq-PT; Tue, 01 Nov 2022 15:23:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434795.687318; Tue, 01 Nov 2022 15:23:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt73-0005gj-Mb; Tue, 01 Nov 2022 15:23:37 +0000
Received: by outflank-mailman (input) for mailman id 434795;
 Tue, 01 Nov 2022 15:23:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt72-0005gZ-NV
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt72-000173-Mt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt72-0002dj-MF
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9/sZxpz21GkOmcpEvnaFwZAHK9k77XAAAjdTFdpiciA=; b=2ZJgY7EYh2sseNy259ERxq+Zdh
	u7qCLAoPu2AEXYJJgCx1d9kaN3KsftG9IW3RuIdAOtq6d8uP3w1dcKwKihQU5qyW9CDOjq7nR/hj5
	K/6pojWwyQ53ty43/Flog9NBPJvrM2mGhFXA9NlSqrWz1zZPRxrL8ohFGN4znzTD66YU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1opt72-0002dj-MF@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:23:36 +0000

commit 8ee7ed7c1ef435f43edc08be07c036d81642d8e1
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit dbef1f7482894c572d90cd73d99ed689c891e863)
---
 tools/xenstore/xenstored_core.c        |  43 +++++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 4 files changed, 109 insertions(+), 51 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 6ea06e20df..85c0d2f38f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -603,7 +603,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -625,7 +625,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1238,13 +1238,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1294,8 +1298,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1580,10 +1588,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
+
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
 
-	if (write_node(conn, node, false))
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
@@ -3003,7 +3028,9 @@ void read_state_node(const void *ctx, const void *state)
 	set_tdb_key(name, &key);
 	if (write_node_raw(NULL, &key, node, true))
 		barf("write node error restoring node");
-	domain_entry_inc(&conn, node);
+
+	if (domain_entry_inc(&conn, node))
+		barf("node accounting error restoring node");
 
 	talloc_free(node);
 }
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 979f8c6298..3c27973fb8 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -369,6 +370,18 @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid)
 	return domain ? : alloc_domain(ctx, domid);
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port, bool restore)
 {
 	int rc;
@@ -788,30 +801,28 @@ void domain_deinit(void)
 		xenevtchn_unbind(xce_handle, virq_port);
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -847,7 +858,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -857,8 +868,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -877,25 +894,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -905,13 +922,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5757a65571..cce13d14f0 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -58,10 +58,10 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ee1b09031a..86caf6c398 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -519,8 +519,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:23:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:23:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434796.687321 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7D-0005jR-RF; Tue, 01 Nov 2022 15:23:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434796.687321; Tue, 01 Nov 2022 15:23:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7D-0005jK-OG; Tue, 01 Nov 2022 15:23:47 +0000
Received: by outflank-mailman (input) for mailman id 434796;
 Tue, 01 Nov 2022 15:23:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7C-0005j7-Qg
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7C-00017K-Py
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7C-0002e9-PO
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=/ZY/2CXgZDWb1QzVxdqhfngcKaaWA9kT13E31H5AI4w=; b=hMxf1ONfeIYXEtKrqF6FMRJibO
	4dNj+m0rAZjaypKZcmKxqJ/4TU3i3lFezASMQ+8+jEdNqAm5tQUdVyqg9LHVdTIO3M0CnBaRKQ7KR
	zOJMbKsgaHnCutCG3sG420a9gVWAFs2uKpTdYyVZioLfRH3orBEOY2IvXjSnxgKYVS/0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1opt7C-0002e9-PO@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:23:46 +0000

commit 1035371fee5552b8cfe9819c4058a4c9e695ba5e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 268369d8e322d227a74a899009c5748d7b0ea142)
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  1 +
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index a16e0c3807..bafc90e2f6 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -63,4 +63,8 @@
 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 85c0d2f38f..050d6f651a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -106,6 +106,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
 
@@ -560,6 +561,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -581,14 +583,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -603,19 +604,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -732,7 +750,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -795,7 +813,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1201,7 +1219,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1475,7 +1493,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1505,7 +1523,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2282,6 +2300,8 @@ static void usage(void)
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2367,6 +2387,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index c0a056ce13..1b3bd5ca56 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -261,6 +261,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 86caf6c398..7bd41eb475 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -260,6 +263,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -297,6 +305,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:23:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:23:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434797.687326 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7N-0005ma-Sr; Tue, 01 Nov 2022 15:23:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434797.687326; Tue, 01 Nov 2022 15:23:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7N-0005mQ-Q3; Tue, 01 Nov 2022 15:23:57 +0000
Received: by outflank-mailman (input) for mailman id 434797;
 Tue, 01 Nov 2022 15:23:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7M-0005mJ-Tm
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7M-00017O-T6
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7M-0002g7-SL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:23:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sW+Ambln4MMtQuQCVVH6h24dWnwk+WN+v5VRSSF692I=; b=ssO1TK8ru/07yv/gLToTJcSriE
	q419WBbwdHjpWTutx3251sXnmsXT6NboKNzBStHE2yEsZ7XQ2CZVTTkMz8lSEjPYBGi10NlgBsdCf
	FpvreI5NQ4nrgynIr3VfxGeuyW3PXA0D+fsVLnmhjxHOv1BNiowII3E8cQzleH9ZcyOU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1opt7M-0002g7-SL@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:23:56 +0000

commit ccef72b6a885714dae0b6f1accb33042ee40e108
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 60e2f6020dea7f616857b8fc1141b1c085d88761)
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 3 +++
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 050d6f651a..51af74390c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1940,7 +1940,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -1979,7 +1980,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(bool live_update)
+void setup_structure(bool live_update)
 {
 	char *tdbname;
 
@@ -2002,6 +2003,7 @@ static void setup_structure(bool live_update)
 		manual_node("/", "tool");
 		manual_node("/tool", "xenstored");
 		manual_node("/tool/xenstored", NULL);
+		domain_entry_fix(dom0_domid, 3, true);
 	}
 
 	check_store();
@@ -2512,9 +2514,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure(live_update);
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init && !live_update) {
 		domain_init(-1);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1b3bd5ca56..459698d840 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -224,6 +224,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(bool live_update);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 struct connection *get_connection_by_id(unsigned int conn_id);
 void check_store(void);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3c27973fb8..0dd75a6a21 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -476,6 +476,9 @@ static struct domain *introduce_domain(const void *ctx,
 		}
 		domain->interface = interface;
 
+		if (is_master_domain)
+			setup_structure(restore);
+
 		/* Now domain belongs to its connection. */
 		talloc_steal(domain->conn, domain);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:24:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:24:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434798.687330 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7X-0005pv-Vc; Tue, 01 Nov 2022 15:24:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434798.687330; Tue, 01 Nov 2022 15:24:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7X-0005pn-Sz; Tue, 01 Nov 2022 15:24:07 +0000
Received: by outflank-mailman (input) for mailman id 434798;
 Tue, 01 Nov 2022 15:24:07 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7X-0005pZ-0i
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:07 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7W-00017n-WE
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:07 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7W-0002h0-VY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=MrBfO6bwBsLKVxaFWxINVKagjrZrxTFg5HNu40HwQWU=; b=6uKIqlktJ/xO0YcF6wahvEfYwD
	iADQHz13GSlv1oeSP+XEovbve5hxCPlW9zPHQHKVVaJOyxh+Y9LTFTSVRKS7bhIogXr6HV2IKb+ZX
	Gw7Zydau7R1KDLRRjPbUjjpThuJcg1gUKHMFcY6ZUEyv9FR4QzMozx8DYTzx1l2rp3MY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1opt7W-0002h0-VY@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:24:06 +0000

commit aa29eb624797fb6825e4a23071c88417672868a4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d4a8ec7a93faedbe54fd197db146de628459e77)
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 51af74390c..eeb0d893e8 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -109,6 +109,8 @@ int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2304,7 +2306,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2331,6 +2340,7 @@ static struct option options[] = {
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2379,7 +2389,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2387,11 +2397,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2409,7 +2424,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2459,7 +2474,10 @@ int main(int argc, char *argv[])
 						 quota_max_path_len);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 459698d840..2fb37dbfe8 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -263,6 +263,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 0dd75a6a21..ec542df6a6 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -76,6 +76,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -296,6 +303,9 @@ bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	if (conn->is_ignored)
@@ -956,6 +966,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index cce13d14f0..571aa46d15 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,6 +65,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:24:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:24:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434799.687333 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7i-0005sb-0r; Tue, 01 Nov 2022 15:24:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434799.687333; Tue, 01 Nov 2022 15:24:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7h-0005sT-UZ; Tue, 01 Nov 2022 15:24:17 +0000
Received: by outflank-mailman (input) for mailman id 434799;
 Tue, 01 Nov 2022 15:24:17 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7h-0005sM-3h
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:17 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7h-00017x-36
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:17 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7h-0002hr-2M
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:17 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=uUalwWtFARYhuJRKpM8OBFLKHUgM/XKxdErebqgY7z8=; b=tRhosVOuBZ88aw5sTy8VkOinux
	wiHWVmKJuoDnILMzzJwLcSrqWci7X406MZjiBRi5wOF7a8ldzufmtoUMCPVJWk7mKMQXXQZVzdclb
	CEuZa6a4FKuMfDBiTxFyBDi4p8x8sagnd3RCT9S4e1Y+7Z9zrpycSOea4whsp232cz6s=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: add memory accounting for responses
Message-Id: <E1opt7h-0002hr-2M@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:24:17 +0000

commit 0113aacb3d791600668cd7703f6f12ed94fc6d03
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    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 f6d00133643a524d2138c9e3f192bbde719050ba)
---
 tools/xenstore/xenstored_core.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index eeb0d893e8..2e02b577c9 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -260,6 +260,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -904,11 +906,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -973,6 +978,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
@@ -2940,6 +2950,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 	 */
 	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
 		domain_outstanding_inc(conn);
+	/*
+	 * We are restoring the state after Live-Update and the new quota may
+	 * be smaller. So ignore it. The limit will be applied for any resource
+	 * after the state has been fully restored.
+	 */
+	domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:24:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:24:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434800.687337 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7s-0005vF-2c; Tue, 01 Nov 2022 15:24:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434800.687337; Tue, 01 Nov 2022 15:24:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt7r-0005v7-WD; Tue, 01 Nov 2022 15:24:28 +0000
Received: by outflank-mailman (input) for mailman id 434800;
 Tue, 01 Nov 2022 15:24:27 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7r-0005uu-6x
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:27 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7r-000182-6G
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:27 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt7r-0002jB-5X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:27 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=YBh6DbvweUGy/Xo4QG2ELmy6p3KRjfcUk87jO0SH3U8=; b=JzpTHgd1aIleG5PQuDydtff61h
	vcAoeGfafH7GwW2jNuConedkHdlWw0pPi0wdS7gun2BhHgl0OcfuWCWBv4tAnEhh0d7HVhHuOCxH2
	7aRxRgG0vxh9Hsm/hbaendiCZNg0Zdzcr8vHnKhJu8KeDMgBvr72+x2THSyXEBhzlhBY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: add memory accounting for watches
Message-Id: <E1opt7r-0002jB-5X@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:24:27 +0000

commit 9c2e71fe0611da9ed2ebbf2362a9bb05d42bf0c3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    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 7f9978a2cc37aaffab2fb09593bc598c0712a69b)
---
 tools/xenstore/xenstored_core.c  |  1 +
 tools/xenstore/xenstored_watch.c | 13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2e02b577c9..b1a4575929 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -457,6 +457,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 1d664e3d6b..0d5858df5b 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -211,7 +211,7 @@ static int check_watch_path(struct connection *conn, const void *ctx,
 }
 
 static struct watch *add_watch(struct connection *conn, char *path, char *token,
-			       bool relative)
+			       bool relative, bool no_quota_check)
 {
 	struct watch *watch;
 
@@ -222,6 +222,9 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	watch->token = talloc_strdup(watch, token);
 	if (!watch->node || !watch->token)
 		goto nomem;
+	if (domain_memory_add(conn->id, strlen(path) + strlen(token),
+			      no_quota_check))
+		goto nomem;
 
 	if (relative)
 		watch->relative_path = get_implicit_path(conn);
@@ -265,7 +268,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (domain_watch(conn) > quota_nb_watch_per_domain)
 		return E2BIG;
 
-	watch = add_watch(conn, vec[0], vec[1], relative);
+	watch = add_watch(conn, vec[0], vec[1], relative, false);
 	if (!watch)
 		return errno;
 
@@ -296,6 +299,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -311,6 +316,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
@@ -373,7 +380,7 @@ void read_state_watch(const void *ctx, const void *state)
 	if (!path)
 		barf("allocation error for read watch");
 
-	if (!add_watch(conn, path, token, relative))
+	if (!add_watch(conn, path, token, relative, true))
 		barf("error adding watch");
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:24:38 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:24:38 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434801.687343 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt82-0005xq-4u; Tue, 01 Nov 2022 15:24:38 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434801.687343; Tue, 01 Nov 2022 15:24:38 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt82-0005xi-1S; Tue, 01 Nov 2022 15:24:38 +0000
Received: by outflank-mailman (input) for mailman id 434801;
 Tue, 01 Nov 2022 15:24:37 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt81-0005xZ-9v
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:37 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt81-00018M-9J
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:37 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt81-0002kS-8c
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:37 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=VL1tXcrBswhUWn/w1S1KRsnlfSSStAHgthE+oXgoEWs=; b=aFor+WT51N6OfWs+MokYtTjZYI
	8thANtXQsk9PuCjxz6UfQA3BG1QarVjkWyge0G3jyyF/mDmgkdyE7aPrbFhEIJsRBLpawBSgXzIwH
	ZKxhSDZBbaf+qgSGXgFV68f3cve3Jf4fk4NG5yg8QeE9Hv5hak0icvKbGvDCFHVfthFU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: add memory accounting for nodes
Message-Id: <E1opt81-0002kS-8c@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:24:37 +0000

commit 32efe29a00efab2896cc973e966a35ecad556495
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    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 b1a4575929..f27d5c0101 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 2fb37dbfe8..5c1b574bff 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 7bd41eb475..ace9a11d77 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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:24:48 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:24:48 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434802.687346 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8C-000614-7j; Tue, 01 Nov 2022 15:24:48 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434802.687346; Tue, 01 Nov 2022 15:24:48 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8C-00060w-54; Tue, 01 Nov 2022 15:24:48 +0000
Received: by outflank-mailman (input) for mailman id 434802;
 Tue, 01 Nov 2022 15:24:47 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8B-00060m-Cw
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:47 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8B-00018W-CI
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:47 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8B-0002lZ-Bj
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:47 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=I4syTjdW8p433CVaiqQsUXixOX3iNvnAf3PkNRcwwHo=; b=ok/7zl6oG1QSEQ05+ISSlnIfEu
	cLoSfj//RArmHtORf9BeKkkSXR7cTo2newCUlc5CtZVECg7um5n6nPgNJQPDPXgPpYFhXIq2Gg8cn
	ySz8MPtB1qlPEo9z+pkxrH6foPAgCwN/VVhcDdawVy6H3pOspJSfK4ZybUffJk/2CHIA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: add exports for quota variables
Message-Id: <E1opt8B-0002lZ-Bj@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:24:47 +0000

commit 1fc3ecc9bfead0a50d8e05de983ed2a8f02fa03c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 1da16d5990b5f7752657fca3e948f735177ea9ad)
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 5c1b574bff..1eb3708f82 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -268,6 +268,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ace9a11d77..28774813de 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static struct accessed_node *find_accessed_node(struct transaction *trans,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 0d5858df5b..4970e9f1a1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:24:58 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:24:58 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434803.687349 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8M-00064K-9B; Tue, 01 Nov 2022 15:24:58 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434803.687349; Tue, 01 Nov 2022 15:24:58 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8M-00064E-6Y; Tue, 01 Nov 2022 15:24:58 +0000
Received: by outflank-mailman (input) for mailman id 434803;
 Tue, 01 Nov 2022 15:24:57 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8L-000642-Ft
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:57 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8L-00018a-FD
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:57 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8L-0002mn-Eg
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:24:57 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=BNjORmYodHxnNmTUP6fxcJXyV9K3Ar1aeutpVxwm1gM=; b=AZzCinGdQ7WYOX1OM79k8uIU87
	spyHmNWy+oU9SC8tPZ0GPf/z+fs2AKcjcj6pqouWAZaWoCMv7Kn1GUhW79QrXMUq3UDXJ15+tZiL3
	gkj7cEFvv4DEE6UFy7FbmJrMOvzMv6nBUvgKRNSKoji69enr0nhpYG0afDNyYksmZHkc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1opt8L-0002mn-Eg@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:24:57 +0000

commit 4d30175fdadb75c55acb8abb186727eda7cd5585
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 334dc8b6fd..a7d006519a 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -366,6 +366,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 211fe1fd9b..980279fa53 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -148,6 +148,115 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "path-max", &quota_max_path_len, "Max. length of a node path" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 #ifdef __MINIOS__
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
@@ -777,6 +886,8 @@ static struct cmd_s cmds[] = {
 	{ "memreport", do_control_memreport, "[<file>]" },
 #endif
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index ec542df6a6..3d51425813 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -351,6 +352,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 571aa46d15..0f883936f4 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -91,6 +91,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:25:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:25:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434804.687355 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8W-000677-BO; Tue, 01 Nov 2022 15:25:08 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434804.687355; Tue, 01 Nov 2022 15:25:08 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8W-00066y-82; Tue, 01 Nov 2022 15:25:08 +0000
Received: by outflank-mailman (input) for mailman id 434804;
 Tue, 01 Nov 2022 15:25:07 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8V-00066g-Ic
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:07 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8V-00018x-I2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:07 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8V-0002oq-HV
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:07 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=7uoLNsrY95aEpXT2ydAY+mO9hxgAdwB+KF8SJ3gA9go=; b=VrCs8d5FSirNU4GrJagxHgTpQb
	TVIlDTym1QDvQqCoS+YHdOrhhhfXOBM/DjAUVPAa4FFYPsJhuGWeq7Isw0s7Y42LtEo3hf+BxpCHq
	6a2cJ1i38k7JfHg8ZmbZ2Ih2wVTbiUb8MACi/VBaTocQ2c760+j5UxhplZ0dCbygpM7E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1opt8V-0002oq-HV@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:25:07 +0000

commit 8fabb963e662a544a397cb2afefb2b15af07ace9
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 84734955d4bf629ba459a74773afcde50a52236f)
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ebe18b8e31..6b06f80859 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -21,9 +21,9 @@ let xs_daemon_socket = Paths.xen_run_stored ^ "/socket"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:25:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:25:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434805.687358 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8g-0006A2-CM; Tue, 01 Nov 2022 15:25:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434805.687358; Tue, 01 Nov 2022 15:25:18 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8g-00069u-9V; Tue, 01 Nov 2022 15:25:18 +0000
Received: by outflank-mailman (input) for mailman id 434805;
 Tue, 01 Nov 2022 15:25:17 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8f-00069n-Lx
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:17 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8f-000192-LG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:17 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8f-0002qB-KK
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:17 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=uzS4G/+n+WdMptpfJJjAdcb+8WWYl83EVnKbErPcsEo=; b=wznMRzMm2xra4rLrebK2y3eziI
	u3WGTLBqE9JB4B2sTFEZuSmZ9Lg7s1tJZOYa5iyvsmHcDRUFvloikvMEkqwtIZqerIUlKSqcxGtTG
	jQ3qtCUghaAIE+QaOf0Z0KDKoupE6IHD0MQCbR63GBr6JSm6GEZDpKuZ2JBxG3MYxhPg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1opt8f-0002qB-KK@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:25:17 +0000

commit 45816222bb3da04f4cd3388efc46d127d48b8906
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    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 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff)
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 27790d4a5c..dd58e6979c 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -389,6 +389,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"
@@ -681,9 +682,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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:25:29 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:25:29 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434806.687363 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8r-0006CR-Ee; Tue, 01 Nov 2022 15:25:29 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434806.687363; Tue, 01 Nov 2022 15:25:29 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt8r-0006CJ-B4; Tue, 01 Nov 2022 15:25:29 +0000
Received: by outflank-mailman (input) for mailman id 434806;
 Tue, 01 Nov 2022 15:25:27 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8p-0006C7-Ok
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:27 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8p-000196-O4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:27 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8p-0002rT-NW
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:27 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5lRC1XYMQtmjb8G/hm4uGC5y81xRAiTZtr36z/EUknE=; b=m4rPsqzSpqJ4dnV+9tE7xUQvNS
	mFfup/1UwkDze7dSRZYr9SMkgS/L/89rtHpcBz2IUvag9/48LFsJlL67xiRLdvd1p5x8k964146PR
	aPAA2NNBXIbjVy6pDlIZUdMQMLm1ZqjPXD63mUmw31DpnHHytJS2ykvy9t/nh7fsbx1A=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml: GC parameter tuning
Message-Id: <E1opt8p-0002rT-NW@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:25:27 +0000

commit 9f89883fabd53cb7873cc31778887ba2a1228dd8
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 4a8bacff20b857ca0d628ef5525877ade11f2a42)
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 6b06f80859..ba63a8147e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index d44ae673c4..3b57ad016d 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -104,6 +104,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -265,6 +266,67 @@ let to_file store cons fds file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -274,6 +336,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:25:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:25:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434807.687366 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt91-0006GB-Ho; Tue, 01 Nov 2022 15:25:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434807.687366; Tue, 01 Nov 2022 15:25:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt91-0006G1-Eq; Tue, 01 Nov 2022 15:25:39 +0000
Received: by outflank-mailman (input) for mailman id 434807;
 Tue, 01 Nov 2022 15:25:37 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8z-0006Fn-Rv
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:37 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8z-00019T-RJ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:37 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt8z-0002tV-QY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:37 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=qt4krfxjRL/rZYzRfB5fYQezrKthe5kZb8Kp2H8HQO0=; b=xxy5Mt3Q7D2582puLDyUSfF1x8
	K+tsx5pP2FctvNhiuVxbk0EKFCR6fLqayOtRYRLBqAj1MVmovefHHvmlxZlBA7ijuLQsJ8VxvbRzp
	sDJbEM565Xe3WIY24/4rM/ERUCUVuk0lxnqbCiHROt1gtKVNs1B9Ba6XmA4DmhPL8B60=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml/libs/xb: hide type of Xb.t
Message-Id: <E1opt8z-0002tV-QY@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:25:37 +0000

commit bbb4ceab25124646fa845855f3cb95ae15d0c3f2
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Fri Jul 29 18:53:29 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml/libs/xb: hide type of Xb.t
    
    Hiding the type will make it easier to change the implementation
    in the future without breaking code that relies on it.
    
    No functional change.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba)
---
 tools/ocaml/libs/xb/xb.ml           | 3 +++
 tools/ocaml/libs/xb/xb.mli          | 9 ++-------
 tools/ocaml/xenstored/connection.ml | 8 ++------
 3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 104d319d77..8404ddd8a6 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out
 let input_len con = Queue.length con.pkt_in
 let has_in_packet con = Queue.length con.pkt_in > 0
 let get_in_packet con = Queue.pop con.pkt_in
+let has_partial_input con = match con.partial_in with
+	| HaveHdr _ -> true
+	| NoHdr (n, _) -> n < Partial.header_size ()
 let has_more_input con =
 	match con.backend with
 	| Fd _         -> false
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 3a00da6cdd..794e35bb34 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,13 +66,7 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
-type t = {
-  backend : backend;
-  pkt_in : Packet.t Queue.t;
-  pkt_out : Packet.t Queue.t;
-  mutable partial_in : partial_buf;
-  mutable partial_out : string;
-}
+type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
 val queue : t -> Packet.t -> unit
@@ -97,6 +91,7 @@ val has_output : t -> bool
 val peek_output : t -> Packet.t
 val input_len : t -> int
 val has_in_packet : t -> bool
+val has_partial_input : t -> bool
 val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 65f99ea6f2..38b47363a1 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -125,9 +125,7 @@ let get_perm con =
 let set_target con target_domid =
 	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
 
-let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with
-	| Xenbus.Xb.Xenmmap _ -> true
-	| _ -> false
+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
 let send_reply con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
@@ -280,9 +278,7 @@ let get_transaction con tid =
 
 let do_input con = Xenbus.Xb.input con.xb
 let has_input con = Xenbus.Xb.has_in_packet con.xb
-let has_partial_input con = match con.xb.Xenbus.Xb.partial_in with
-	| HaveHdr _ -> true
-	| NoHdr (n, _) -> n < Xenbus.Partial.header_size ()
+let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:25:49 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:25:49 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434808.687370 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9B-0006JA-JS; Tue, 01 Nov 2022 15:25:49 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434808.687370; Tue, 01 Nov 2022 15:25:49 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9B-0006J0-GL; Tue, 01 Nov 2022 15:25:49 +0000
Received: by outflank-mailman (input) for mailman id 434808;
 Tue, 01 Nov 2022 15:25:48 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt99-0006Im-V8
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:47 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt99-00019Z-UV
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:47 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt99-0002uD-Tm
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:47 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=1liEwibVeNlzHAYVziwBgSDg/zKGqgquUKqRjdDK81c=; b=UDkkzRW38N87k85eRNzdgmjNnv
	3EuaM3a7sBb6qUVVahYCpyaAchUEOBq82V+LDg8oKI+3s+N0rO5uEJxbMYNXfTuffweTRVCqir5Eb
	Soe9ZPCtOHk5wogz3bQP9gksbRVmvnbb72958XtN5JL0tJN5ekTgrkkB89/MtTFwEz2U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1opt99-0002uD-Tm@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:25:47 +0000

commit fccdca83a4425b0e30ec9e29e9a5909e1a55b80d
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c0a86a462721008eca5ff733660de094d3c34bc7)
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  4 +---
 tools/ocaml/xenstored/process.ml    | 15 +++++++--------
 5 files changed, 20 insertions(+), 42 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 38b47363a1..cc20e047d2 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,9 +277,7 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
@@ -307,7 +305,7 @@ let is_bad con = match con.dom with None -> false | Some dom -> Domain.is_bad_do
    Restrictions below can be relaxed once xenstored learns to dump more
    of its live state in a safe way *)
 let has_extra_connection_data con =
-	let has_in = has_input con || has_partial_input con in
+	let has_in = has_partial_input con in
 	let has_out = has_output con in
 	let has_socket = con.dom = None in
 	let has_nondefault_perms = make_perm con.dom <> con.perm in
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index dd58e6979c..cbf7082137 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -195,10 +195,9 @@ let parse_live_update args =
 			| _ when Unix.gettimeofday () < t.deadline -> false
 			| l ->
 				warn "timeout reached: have to wait, migrate or shutdown %d domains:" (List.length l);
-				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, in: %b, out: %b, perm: %s"
+				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, out: %b, perm: %s"
 					(Connection.get_domstr con)
 					(Connection.number_of_transactions con)
-					(Connection.has_input con)
 					(Connection.has_output con)
 					(Connection.get_perm con |> Perms.Connection.to_string)
 					) l in
@@ -706,16 +705,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -725,8 +725,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:25:59 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:25:59 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434809.687374 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9L-0006Lw-KQ; Tue, 01 Nov 2022 15:25:59 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434809.687374; Tue, 01 Nov 2022 15:25:59 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9L-0006Lp-Hv; Tue, 01 Nov 2022 15:25:59 +0000
Received: by outflank-mailman (input) for mailman id 434809;
 Tue, 01 Nov 2022 15:25:58 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9K-0006Lf-1y
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:58 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9K-00019d-1E
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:58 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9K-0002us-0Z
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:25:58 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=k4oVjpQkicf3gBxJ5XRuo8vyxiUtsl6JoChYJQtUwtE=; b=0+8SHa6DomoYEgfqMWRf/GXzZz
	xYGd8YyhY2m5k9gaC/t9hcmQ3mii6fUP36mPBlV3LE7JDbmSuRq6PNvpJ9bmNUB4hP8qtONXT0f+1
	5j1gvtpAKbqaQjh4pRfMZ4gOfiwBh0W6UV5OUePPAW9laD1SHT673UUiyjjYRzp98ibw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1opt9K-0002us-0Z@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:25:58 +0000

commit 9e5290daf923e84ca56a6f3d9fc6a333175ef0f9
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 19171fb5d888b4467a7073e8febc5e05540956e9)
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:26:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:26:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434810.687378 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9V-0006Oh-Me; Tue, 01 Nov 2022 15:26:09 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434810.687378; Tue, 01 Nov 2022 15:26:09 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9V-0006Oa-JV; Tue, 01 Nov 2022 15:26:09 +0000
Received: by outflank-mailman (input) for mailman id 434810;
 Tue, 01 Nov 2022 15:26:08 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9U-0006OJ-4s
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:08 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9U-0001A1-4D
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:08 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9U-0002vr-3d
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:08 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5vJe5T7YHcJ1IsynuN/DV53SZcTybtjNixftfOR38Vk=; b=mrRUynAjbxFEhTt69SC/MhHCQF
	B1hlIkkv2COE/0aThrSQAPVMdbPFaS0QY+kos3wl2ObVK9xU0gJHLrOO6HVAfzfTsayGqJLvkgY7M
	CEUUxd/acgAbl3vv8DGv8j5AbMC/AdJiZ+0oT1aR8A/vrXze2VG8DVcl8pMX+rgqV7Ww=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1opt9U-0002vr-3d@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:26:08 +0000

commit 64048b4c218099b6adcf46cd7b4d1dc9c658009e
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96)
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index cc20e047d2..9624a5f9da 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -280,6 +408,7 @@ let do_input con = Xenbus.Xb.input con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -323,7 +452,7 @@ let prevents_live_update con = not (is_bad con)
 	&& (has_extra_connection_data con || has_transaction_data con)
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 3c7429fe7f..7d68c583b4 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: Connection.watch list Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -197,6 +216,16 @@ let debug cons =
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
 
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
+
 let filter ~f cons =
 	let fold _ v acc = if f v then v :: acc else acc in
 	[]
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ba63a8147e..327b6d795e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -24,6 +24,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index cbf7082137..ce39ce28b5 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -57,7 +57,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -67,8 +67,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -234,6 +235,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -342,7 +357,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -501,7 +516,7 @@ let do_watch con t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -532,7 +547,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -700,7 +715,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -728,6 +744,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 3b57ad016d..c799e20f11 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:26:19 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:26:19 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434811.687382 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9f-0006Rp-QD; Tue, 01 Nov 2022 15:26:19 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434811.687382; Tue, 01 Nov 2022 15:26:19 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9f-0006Rh-NX; Tue, 01 Nov 2022 15:26:19 +0000
Received: by outflank-mailman (input) for mailman id 434811;
 Tue, 01 Nov 2022 15:26:18 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9e-0006RY-7Z
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:18 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9e-0001AB-6x
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:18 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9e-0002wQ-6Q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:18 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=po4XiBmkNJmzD73upHXwhekFXDqGQVXE/iJ2HWrc/S8=; b=Hgzj6LvOMhVzpYO8hq0V7MvrIL
	TivOfi6TJdnSqv7j6Tp+nllhYlmkgxvUnM84yH7E8YUiRpLA49636YU1BBDS3MWSXz/ESqmqcwtTQ
	eE6kIMfV6YafEfdBRQ39GtRY8mxCBkBFo9z45zYInU9Jbh36pgNVwxvbLU+Q/W5JWC9I=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1opt9e-0002wQ-6Q@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:26:18 +0000

commit 26faa6b55881445c25e7e83613c2354090fdff18
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c7bc20d8d123851a468402bbfc9e3330efff21ec)
---
 SUPPORT.md | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index 0fb262f81f..48fb462221 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -179,13 +179,18 @@ Support for running qemu-xen device model in a linux stubdomain.
 
     Status: Tech Preview
 
-## Liveupdate of C xenstored daemon
+## Xenstore
 
-    Status: Tech Preview
+### C xenstored daemon
 
-## Liveupdate of OCaml xenstored daemon
+    Status: Supported
+    Status, Liveupdate: Tech Preview
 
-    Status: Tech Preview
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+    Status, Liveupdate: Not functional
 
 ## Toolstack/3rd party
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:26:30 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:26:30 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434812.687385 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9p-0006V7-SA; Tue, 01 Nov 2022 15:26:29 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434812.687385; Tue, 01 Nov 2022 15:26:29 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9p-0006V0-P3; Tue, 01 Nov 2022 15:26:29 +0000
Received: by outflank-mailman (input) for mailman id 434812;
 Tue, 01 Nov 2022 15:26:28 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9o-0006Un-Ak
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:28 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9o-0001AF-A4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:28 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9o-0002xL-9X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:28 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=4ZSEYrh5oCE9otyraYOL86S3GWNPxIi7SQ0j8c34AtE=; b=hAylBv6OrUoUic+82090m2CFVU
	uFdFKHIiW0B03A5/Uw+J4nUV+cdhABkA/8DE7bWsG39NTA7aFI9nGBOs8kGzzoaDRMqX5fP6tnEcm
	akz03AGrQ5uO7KiHgcW6droVc9Sq0YdY0Y9p6SGpGTYORtizXvVzA63rwYm0g9NGi+Vk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1opt9o-0002xL-9X@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:26:28 +0000

commit 607e186fe094f8d1c78572cd3b1f7a43730203c1
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2a587de219cc0765330fbf9fac6827bfaf29e29b)
---
 tools/xenstore/xenstored_control.c     | 31 +++++++-------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 29 +++++++------
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 118 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 980279fa53..95a60bf578 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -107,7 +107,7 @@ static const char *lu_begin(struct connection *conn)
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 	/*
 	 * max_pars can be used to limit the size of the parameter vector,
@@ -119,7 +119,7 @@ struct cmd_s {
 	unsigned int max_pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -131,7 +131,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -233,7 +233,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -245,7 +245,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -258,7 +258,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 }
 
 #ifdef __MINIOS__
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	if (num)
@@ -270,7 +270,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 #else
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -285,7 +285,7 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -325,7 +325,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -802,7 +802,7 @@ static const char *lu_start(const void *ctx, struct connection *conn,
 	return NULL;
 }
 
-static int do_control_lu(void *ctx, struct connection *conn,
+static int do_control_lu(const void *ctx, struct connection *conn,
 			 char **vec, int num)
 {
 	const char *ret = NULL;
@@ -852,7 +852,7 @@ static int do_control_lu(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -891,7 +891,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd, len = 0;
@@ -927,7 +927,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	unsigned int cmd, num, off;
 	char **vec = NULL;
@@ -947,11 +948,11 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (cmds[cmd].max_pars)
 		num = min(num, cmds[cmd].max_pars);
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) < num)
 		return EIO;
 
-	return cmds[cmd].func(in, conn, vec + 1, num - 1);
+	return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index aac61f0590..6430c37693 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,5 +16,6 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 void lu_read_state(void);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f27d5c0101..806f24bbab 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1214,11 +1214,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1227,7 +1229,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1239,7 +1241,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1266,7 +1269,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1282,11 +1285,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1476,7 +1481,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1490,12 +1496,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1506,18 +1512,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1527,10 +1534,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 			return errno;
 		if (!name)
 			return ENOMEM;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1628,24 +1635,25 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
 			if (!name)
 				return ENOMEM;
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1660,7 +1668,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1670,13 +1678,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1689,7 +1699,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1706,7 +1717,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1721,7 +1732,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1756,7 +1767,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1764,7 +1775,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1840,6 +1852,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	if ((unsigned int)type >= XS_TYPE_COUNT || !wire_funcs[type].func) {
 		eprintf("Client unknown operation %i", type);
@@ -1860,10 +1873,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3d51425813..d262f4e9db 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -336,7 +336,7 @@ bool domain_can_write(struct connection *conn)
 	return ((intf->rsp_prod - intf->rsp_cons) != XENSTORE_RING_SIZE);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -540,7 +540,8 @@ static struct domain *introduce_domain(const void *ctx,
 }
 
 /* domid, gfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -558,7 +559,7 @@ int do_introduce(struct connection *conn, struct buffered_data *in)
 	if (port <= 0)
 		return EINVAL;
 
-	domain = introduce_domain(in, domid, port, false);
+	domain = introduce_domain(ctx, domid, port, false);
 	if (!domain)
 		return errno;
 
@@ -581,7 +582,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -625,7 +627,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -640,7 +643,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -655,7 +659,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -663,18 +668,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -695,7 +699,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 0f883936f4..da513443cd 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -24,25 +24,32 @@ void handle_event(void);
 void check_domains(bool restore);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(int evtfd);
 void dom0_init(void);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 28774813de..3e3eb47326 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -481,7 +481,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -494,8 +495,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -544,7 +545,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -562,8 +564,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	if (!conn->transaction_started)
 		conn->ta_start_time = 0;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 4970e9f1a1..854bbcad6e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -243,7 +243,7 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	return NULL;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -252,7 +252,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	errno = check_watch_path(conn, in, &(vec[0]), &relative);
+	errno = check_watch_path(conn, ctx, &(vec[0]), &relative);
 	if (errno)
 		return errno;
 
@@ -283,7 +283,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -291,7 +292,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 0e693f0839..091890edca 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:26:40 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:26:40 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434813.687390 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9z-0006YD-Vk; Tue, 01 Nov 2022 15:26:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434813.687390; Tue, 01 Nov 2022 15:26:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1opt9z-0006Y5-Sv; Tue, 01 Nov 2022 15:26:39 +0000
Received: by outflank-mailman (input) for mailman id 434813;
 Tue, 01 Nov 2022 15:26:38 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9y-0006Xv-Dh
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:38 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9y-0001CA-D5
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:38 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1opt9y-0002xp-CY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:38 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0d92Q34OuQdfzhyQ1CgKebj84AcJHbmo2aSOgZsftNE=; b=UNPZiv+Mj0h8laaqlcjxCzDwDA
	L0bfNTeg6fLkGKQI6YYs5X5U7ipp7/YyILerQQy31FjArhp9tBkTD1omB9jbUgWLLs0DGx/DNfCnq
	hduhS2OmVxZdUoWpM1+9WxR0K+8isCe8VRJ9++xNpMYCKpSvvWMrdJ9k/MUD1wDG4mX8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: fix checking node permissions
Message-Id: <E1opt9y-0002xp-CY@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:26:38 +0000

commit 8012324cb9e676bd342a5adfda1700525f195e2e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ab128218225d3542596ca3a02aee80d55494bef8)
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 806f24bbab..8aecd425f2 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1723,6 +1723,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index d262f4e9db..8b503c2dfe 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -881,7 +881,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -889,20 +888,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -915,8 +932,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -933,8 +948,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index da513443cd..0b4f56b814 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -66,6 +66,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:26:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:26:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434815.687394 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAA-0006bD-0x; Tue, 01 Nov 2022 15:26:50 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434815.687394; Tue, 01 Nov 2022 15:26:49 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optA9-0006b5-UV; Tue, 01 Nov 2022 15:26:49 +0000
Received: by outflank-mailman (input) for mailman id 434815;
 Tue, 01 Nov 2022 15:26:48 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optA8-0006as-Gj
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:48 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optA8-0001CE-G8
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:48 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optA8-0002yv-FN
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:48 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=C9DvIFgWGEAY9/oc5bglApJ+yhzLwhbpQJh5ujU1t54=; b=RoMa5z9RrNI/6rKdzjRXxE5ptN
	Rh4BKywmx/WJ1vjYDSdpXH4pl07ctTpE8hqEZ4oAJl6kPEuPem8YdSsQ+RSZIokcmyS1h8Jyrys/c
	ujT9KStO8Yew8Xa4YQamH+Lre8qcXbfdce7RM8v2R0DouT12UXIUaR6A/DB/NSYK1ciM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1optA8-0002yv-FN@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:26:48 +0000

commit 62755d0a90344e704062e7b6943a3fa2dc5e02e6
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 86 ++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 31 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8aecd425f2..46a37e5257 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1343,45 +1343,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name)
 static struct node *construct_node(struct connection *conn, const void *ctx,
 				   const char *name)
 {
-	struct node *parent, *node;
-	char *parentname = get_parent(ctx, name);
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
 
 	if (!parentname)
 		return NULL;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
 
-	/* Add child to parent. */
-	if (add_child(ctx, parent, name))
-		goto nomem;
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
 
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
 
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:27:00 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:27:00 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434816.687397 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAK-0006eF-2U; Tue, 01 Nov 2022 15:27:00 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434816.687397; Tue, 01 Nov 2022 15:27:00 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAJ-0006e7-W3; Tue, 01 Nov 2022 15:26:59 +0000
Received: by outflank-mailman (input) for mailman id 434816;
 Tue, 01 Nov 2022 15:26:58 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAI-0006e0-Jy
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:58 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAI-0001CI-JJ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:58 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAI-0002za-IU
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:26:58 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=V7iVShNeV2DSTxdC0amS/7yvjUFiB5RXiIhVh34I7QY=; b=aD74dFXwQzbpAC712WQxFtAuEO
	OcoSljhuFvJD389fZCyVpAL51aMddKbc5Rwa4ci7Mnkgy7WaZlvmlGU9PCDUSoo9Sz3UIIrJAJ0NZ
	hVGDz4fTB02JyDWRWY117I6JcTN48goVdM39Pcf+X7g2va6Lo6+6wh2R0JmMkT5qPfDg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1optAI-0002za-IU@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:26:58 +0000

commit b9a005b0b4520261c6c362fca55500782837f119
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4)
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 46a37e5257..4c3897721b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1574,15 +1574,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1592,7 +1592,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2226,6 +2228,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2278,12 +2291,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2300,11 +2308,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:27:12 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:27:12 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434817.687402 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAU-0006iQ-4P; Tue, 01 Nov 2022 15:27:10 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434817.687402; Tue, 01 Nov 2022 15:27:10 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAU-0006iJ-1Y; Tue, 01 Nov 2022 15:27:10 +0000
Received: by outflank-mailman (input) for mailman id 434817;
 Tue, 01 Nov 2022 15:27:08 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAS-0006i7-Os
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:08 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAS-0001CZ-MD
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:08 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAS-00030I-Le
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:08 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8yEUzK+86LOjcNR48UC3VAsd/WivL4is/K6ACCl9Wes=; b=kwomsK/Fr2pjLWtKe4PW9/puKh
	/3zYHtwLOccxRMgMRTjcfVu/3oGuPEt1c5A7d57Ms3pOQAWmgDR0BuhPajrP/Tm4KSyXz2+fqjocR
	ycqD0G3WqCR8m/nCXSn5xaKfu2AcEhSL0nm5FruJOGCUsKCVdBfN53VnawgWB29MW3PM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: add generic treewalk function
Message-Id: <E1optAS-00030I-Le@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:27:08 +0000

commit 83b6c511a5989a83c50daae83c5b5a683d6dc096
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d7c5d19bc27492360196e7dad2b227908564fff)
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 4c3897721b..7463d0a002 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1804,6 +1804,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2206,18 +2335,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2277,7 +2394,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1eb3708f82..f0fd8c3528 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -195,6 +195,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -334,6 +335,45 @@ void read_state_buffered_data(const void *ctx, struct connection *conn,
 			      const struct xs_state_connection *sc);
 void read_state_node(const void *ctx, const void *state);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:27:20 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:27:20 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434818.687405 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAe-0006lT-6L; Tue, 01 Nov 2022 15:27:20 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434818.687405; Tue, 01 Nov 2022 15:27:20 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAe-0006lM-3L; Tue, 01 Nov 2022 15:27:20 +0000
Received: by outflank-mailman (input) for mailman id 434818;
 Tue, 01 Nov 2022 15:27:18 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAc-0006lA-Pr
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:18 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAc-0001Cn-PE
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:18 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAc-00030j-Oh
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:18 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=CV1hji/m55zt3b8Ld044kha2wTp7Z9yV6e++DwoyCu0=; b=YFb7Es2/hpbZRoS6Sr98TzziCo
	QhgOmGi5T9qka5VDyDkZTpSDz49ViSfsN7MDSJCHuufJyS485msz9hdgF/aPBVd8wH0pKthSmsAa1
	88SaFEub04allvP08xwVgXFhogFgqtBM6CrlVhVQqQhVUW6v03BfSG/iZIDpd7ed3esA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: simplify check_store()
Message-Id: <E1optAc-00030j-Oh@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:27:18 +0000

commit 4096512a70fd0bb65e40ed4269a1ca74dbb16220
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 70f719f52a220bc5bc987e4dd28e14a7039a176b)
---
 tools/xenstore/xenstored_core.c | 47 +++++++++++++----------------------------
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 7463d0a002..a48255c64c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2378,50 +2378,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-		if (!children) {
-			log("check_store create table: ENOMEM");
-			return ENOMEM;
-		}
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2431,19 +2415,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:27:29 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:27:29 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434819.687409 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAn-0006oi-9b; Tue, 01 Nov 2022 15:27:29 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434819.687409; Tue, 01 Nov 2022 15:27:29 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAn-0006ob-76; Tue, 01 Nov 2022 15:27:29 +0000
Received: by outflank-mailman (input) for mailman id 434819;
 Tue, 01 Nov 2022 15:27:28 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAm-0006oU-Sy
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:28 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAm-0001D2-SG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:28 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAm-00031K-Re
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:28 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=oauZpmLeHJrW0lqAeMEOgGGkgqZCKjtB6+TAbLqzxdo=; b=VWEcX4qYPInUaLxMOi34HkkCfY
	K64L6AstvwFlE/MR7ZaCdECEAm2D0u+bP+oi57WAW8pOc8cUGrW/+LCH/5F1ONvPO40sYenikj5Lv
	jqPSnoFPjDamEkVg7d781uP/ROqqlwYMF9VfGIO6016dHJmb2Xt8lEeqbhtF5QavZGBo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: use treewalk for check_store()
Message-Id: <E1optAm-00031K-Re@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:27:28 +0000

commit a95277ee36e1db2f67e8091f4ea401975d341659
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index a48255c64c..ed8bc9b02e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2345,18 +2345,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2370,70 +2358,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
-
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
-
-			childnode = read_node(NULL, childname, childname);
+	struct hashtable *reachable = arg;
 
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2482,24 +2429,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char * root = talloc_strdup(NULL, "/");
-	struct hashtable * reachable =
-		create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
+
+	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
 		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:27:39 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:27:39 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434820.687414 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAx-0006rt-BU; Tue, 01 Nov 2022 15:27:39 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434820.687414; Tue, 01 Nov 2022 15:27:39 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optAx-0006rl-8l; Tue, 01 Nov 2022 15:27:39 +0000
Received: by outflank-mailman (input) for mailman id 434820;
 Tue, 01 Nov 2022 15:27:39 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAw-0006rf-Vw
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:38 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAw-0001DP-VI
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:38 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optAw-00031l-Ue
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:38 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5VNitPP7c0NUNXkV5uEwTQYBIXn1NkvOVNSVEVU9aXc=; b=0UwPF1seZgQ2kFPEycL25vpHq4
	ihdwx5LtbmCgWhi8rWkyHMBOJ3ExDLcsPbDcpDu/IOQLBbIL3pIGNIG0YMdBQsM4Gt/He40mgRBSz
	Ah9QXDYGuAhQTzMq2892LUnDHz46jZaGOs46gukB6jkZouF1WKBIr1N+u07igpqK2bbA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1optAw-00031l-Ue@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:27:38 +0000

commit 9ead5845034c04a5c6e04d9b069d9c13141f4f33
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ea16962053a6849a6e7cada549ba7f8c586d85c6)
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ed8bc9b02e..9576411757 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1300,21 +1300,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1585,69 +1570,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1655,9 +1630,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1694,7 +1681,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:27:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:27:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434821.687418 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optB8-0006uh-DU; Tue, 01 Nov 2022 15:27:50 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434821.687418; Tue, 01 Nov 2022 15:27:50 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optB8-0006ua-AN; Tue, 01 Nov 2022 15:27:50 +0000
Received: by outflank-mailman (input) for mailman id 434821;
 Tue, 01 Nov 2022 15:27:49 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optB7-0006uK-31
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:49 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optB7-0001DT-2I
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:49 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optB7-00032E-1Q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:49 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=dcIgYlC4zFrksJI9M9Uglvv2DSi2MKPyvp2anYJ3fps=; b=FoOhqGz8IUgVGuTMQXE3YCvOix
	Mg3SukRPlYwBI+7yjl6+tX75VM4kGcai5I+qw3kJnaFg2IXKRWQfJ1Az95MkGOLcZ8j85mA1/2bOy
	pLSQBV8d7H97WrHtT8K7qmP9D6jYJWz05zxIVeoWhG43WOjipbjtYv23XB7MaCqZT9Ac=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: use treewalk for creating node records
Message-Id: <E1optB7-00032E-1Q@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:27:49 +0000

commit 84674f206778e9b3d8d67c6c76aa8094a262d5ec
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: use treewalk for creating node records
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when creating the node records during a live update.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 297ac246a5d8ed656b349641288f3402dcc0251e)
---
 tools/xenstore/xenstored_core.c   | 127 ++++++++++++++++----------------------
 tools/xenstore/xenstored_core.h   |   3 +-
 tools/xenstore/xenstored_domain.c |   2 +-
 3 files changed, 54 insertions(+), 78 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9576411757..e8cdfeef50 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2990,132 +2990,109 @@ const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 	return NULL;
 }
 
-const char *dump_state_node_perms(FILE *fp, struct xs_state_node *sn,
-				  const struct xs_permissions *perms,
+const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
 				  unsigned int n_perms)
 {
 	unsigned int p;
 
 	for (p = 0; p < n_perms; p++) {
+		struct xs_state_node_perm sp;
+
 		switch ((int)perms[p].perms & ~XS_PERM_IGNORE) {
 		case XS_PERM_READ:
-			sn->perms[p].access = XS_STATE_NODE_PERM_READ;
+			sp.access = XS_STATE_NODE_PERM_READ;
 			break;
 		case XS_PERM_WRITE:
-			sn->perms[p].access = XS_STATE_NODE_PERM_WRITE;
+			sp.access = XS_STATE_NODE_PERM_WRITE;
 			break;
 		case XS_PERM_READ | XS_PERM_WRITE:
-			sn->perms[p].access = XS_STATE_NODE_PERM_BOTH;
+			sp.access = XS_STATE_NODE_PERM_BOTH;
 			break;
 		default:
-			sn->perms[p].access = XS_STATE_NODE_PERM_NONE;
+			sp.access = XS_STATE_NODE_PERM_NONE;
 			break;
 		}
-		sn->perms[p].flags = (perms[p].perms & XS_PERM_IGNORE)
+		sp.flags = (perms[p].perms & XS_PERM_IGNORE)
 				     ? XS_STATE_NODE_PERM_IGNORE : 0;
-		sn->perms[p].domid = perms[p].id;
-	}
+		sp.domid = perms[p].id;
 
-	if (fwrite(sn->perms, sizeof(*sn->perms), n_perms, fp) != n_perms)
-		return "Dump node permissions error";
+		if (fwrite(&sp, sizeof(sp), 1, fp) != 1)
+			return "Dump node permissions error";
+	}
 
 	return NULL;
 }
 
-static const char *dump_state_node_tree(FILE *fp, char *path)
+struct dump_node_data {
+	FILE *fp;
+	const char *err;
+};
+
+static int dump_state_node_err(struct dump_node_data *data, const char *err)
+{
+	data->err = err;
+	return WALK_TREE_ERROR_STOP;
+}
+
+static int dump_state_node(const void *ctx, struct connection *conn,
+			   struct node *node, void *arg)
 {
-	unsigned int pathlen, childlen, p = 0;
+	struct dump_node_data *data = arg;
+	FILE *fp = data->fp;
+	unsigned int pathlen;
 	struct xs_state_record_header head;
 	struct xs_state_node sn;
-	TDB_DATA key, data;
-	const struct xs_tdb_record_hdr *hdr;
-	const char *child;
 	const char *ret;
 
-	pathlen = strlen(path) + 1;
-
-	set_tdb_key(path, &key);
-	data = tdb_fetch(tdb_ctx, key);
-	if (data.dptr == NULL)
-		return "Error reading node";
-
-	/* Clean up in case of failure. */
-	talloc_steal(path, data.dptr);
-
-	hdr = (void *)data.dptr;
+	pathlen = strlen(node->name) + 1;
 
 	head.type = XS_STATE_TYPE_NODE;
 	head.length = sizeof(sn);
 	sn.conn_id = 0;
 	sn.ta_id = 0;
 	sn.ta_access = 0;
-	sn.perm_n = hdr->num_perms;
+	sn.perm_n = node->perms.num;
 	sn.path_len = pathlen;
-	sn.data_len = hdr->datalen;
-	head.length += hdr->num_perms * sizeof(*sn.perms);
+	sn.data_len = node->datalen;
+	head.length += node->perms.num * sizeof(*sn.perms);
 	head.length += pathlen;
-	head.length += hdr->datalen;
+	head.length += node->datalen;
 	head.length = ROUNDUP(head.length, 3);
 
 	if (fwrite(&head, sizeof(head), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node head error");
 	if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node state error");
 
-	ret = dump_state_node_perms(fp, &sn, hdr->perms, hdr->num_perms);
+	ret = dump_state_node_perms(fp, node->perms.p, node->perms.num);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
 
-	if (fwrite(path, pathlen, 1, fp) != 1)
-		return "Dump node path error";
-	if (hdr->datalen &&
-	    fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1)
-		return "Dump node data error";
+	if (fwrite(node->name, pathlen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node path error");
+
+	if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node data error");
 
 	ret = dump_state_align(fp);
 	if (ret)
-		return ret;
-
-	child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen;
-
-	/*
-	 * Use path for constructing children paths.
-	 * As we don't write out nodes without having written their parent
-	 * already we will never clobber a part of the path we'll need later.
-	 */
-	pathlen--;
-	if (path[pathlen - 1] != '/') {
-		path[pathlen] = '/';
-		pathlen++;
-	}
-	while (p < hdr->childlen) {
-		childlen = strlen(child) + 1;
-		if (pathlen + childlen > XENSTORE_ABS_PATH_MAX)
-			return "Dump node path length error";
-		strcpy(path + pathlen, child);
-		ret = dump_state_node_tree(fp, path);
-		if (ret)
-			return ret;
-		p += childlen;
-		child += childlen;
-	}
-
-	talloc_free(data.dptr);
+		return dump_state_node_err(data, ret);
 
-	return NULL;
+	return WALK_TREE_OK;
 }
 
 const char *dump_state_nodes(FILE *fp, const void *ctx)
 {
-	char *path;
-
-	path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX);
-	if (!path)
-		return "Path buffer allocation error";
+	struct dump_node_data data = {
+		.fp = fp,
+		.err = "Dump node walk error"
+	};
+	struct walk_funcs walkfuncs = { .enter = dump_state_node };
 
-	strcpy(path, "/");
+	if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data))
+		return data.err;
 
-	return dump_state_node_tree(fp, path);
+	return NULL;
 }
 
 void read_state_global(const void *ctx, const void *state)
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index f0fd8c3528..3190494bbe 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -326,8 +326,7 @@ const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 				     const struct connection *conn,
 				     struct xs_state_connection *sc);
 const char *dump_state_nodes(FILE *fp, const void *ctx);
-const char *dump_state_node_perms(FILE *fp, struct xs_state_node *sn,
-				  const struct xs_permissions *perms,
+const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
 				  unsigned int n_perms);
 
 void read_state_global(const void *ctx, const void *state);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8b503c2dfe..a91cc75ab5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -1449,7 +1449,7 @@ static const char *dump_state_special_node(FILE *fp, const char *name,
 	if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
 		return "Dump special node error";
 
-	ret = dump_state_node_perms(fp, &sn, perms->p, perms->num);
+	ret = dump_state_node_perms(fp, perms->p, perms->num);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:28:00 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:28:00 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434822.687422 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBI-0006xl-Fa; Tue, 01 Nov 2022 15:28:00 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434822.687422; Tue, 01 Nov 2022 15:28:00 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBI-0006xd-CA; Tue, 01 Nov 2022 15:28:00 +0000
Received: by outflank-mailman (input) for mailman id 434822;
 Tue, 01 Nov 2022 15:27:59 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBH-0006xV-65
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:59 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBH-0001DZ-5T
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:59 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBH-00032f-4i
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:27:59 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=tNtUoabHbDfAuLm00b9X7W8gnDDx157OM3VSVDOxFL8=; b=XazZWl+VwiIf2K2m+MWkJNGf5A
	KYnzOS6BETcUP5WYnuJvo1qwoMYFrDYKxO0fqwdnmy5PldhtjD1iRy8h03nMT5iWMjub5VSmbeHYw
	u/06s3dqd2MzFBKnwuKuoggI+A+hZZXKsYdVeYZWm8wBl1/RGN/OGQN8EDz4+GNwumvs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1optBH-00032f-4i@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:27:59 +0000

commit da87661d058c4a6cf2ea6439771b9834f1c06223
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 755d3f9debf8879448211fffb018f556136f6a79)
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 84 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 80 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e8cdfeef50..d5b2e59b0d 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -80,6 +80,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -722,7 +723,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -765,7 +766,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1617,7 +1618,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1681,7 +1682,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2537,6 +2538,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2561,6 +2564,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 #ifndef NO_LIVE_UPDATE
@@ -2641,7 +2645,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2677,6 +2681,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 3190494bbe..9a9dbb2c3c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -233,6 +233,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(bool live_update);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 struct connection *get_connection_by_id(unsigned int conn_id);
@@ -279,6 +282,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index a91cc75ab5..ee4b19387d 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -196,10 +196,64 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		set_tdb_key(node->name, &key);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -857,15 +911,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -926,23 +980,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -960,15 +1002,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1087,7 +1129,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 0b4f56b814..491d7a325b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,7 +65,7 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:28:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:28:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434823.687425 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBS-000715-Io; Tue, 01 Nov 2022 15:28:10 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434823.687425; Tue, 01 Nov 2022 15:28:10 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBS-00070x-G8; Tue, 01 Nov 2022 15:28:10 +0000
Received: by outflank-mailman (input) for mailman id 434823;
 Tue, 01 Nov 2022 15:28:09 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBR-00070n-9Q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:09 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBR-0001Dx-8i
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:09 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBR-000342-7q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:09 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=+/VM74HxswFX55aCx+ucYEyCJqMwwWnLH+16CoNgnqs=; b=Ty5KxlDVJC8A1FmwGJbkJyxwX8
	6avDXLmnbQI+EaxKRc5nHDoeDpszxWG1S2TCvgsF4Ubutgdr8EV6HvrxtNME2PRMDXHf10Xec7Ue1
	1RDOSSrl1Bbmw0AATZ+/mDwud3NyXg/j2I0tA9nTA9A/VxXMKxRHX3DBN/k5DtbgrrFo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: make the internal memory data base the default
Message-Id: <E1optBR-000342-7q@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:28:09 +0000

commit 4269999ecedf79452a3fbbfab842f045d1ece16e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d174fefa90487ddd25ebc618028f67b2e8a1f795)
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 32689abd74..d080dae5d3 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -214,9 +214,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom->cmdline = xc_dom_strdup(dom, cmdline);
     dom->xenstore_domid = domid;
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index d5b2e59b0d..9ddbd934f7 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2230,7 +2230,7 @@ static void accept_connection(int sock)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2537,7 +2537,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2563,7 +2564,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2645,7 +2646,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2679,7 +2681,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:28:20 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:28:20 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434824.687430 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBc-00073z-Kr; Tue, 01 Nov 2022 15:28:20 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434824.687430; Tue, 01 Nov 2022 15:28:20 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBc-00073q-Ho; Tue, 01 Nov 2022 15:28:20 +0000
Received: by outflank-mailman (input) for mailman id 434824;
 Tue, 01 Nov 2022 15:28:19 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBb-00073c-CL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:19 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBb-0001E7-Bk
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:19 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBb-000350-Az
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:19 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=gkLeeylARhGNfo9Yr7jzi2tJ469bQyXR3gNjn7lNxOY=; b=lc+EIQ1/Ma3YRBpJ5EE3YrSZ+G
	U2qOFuOhiEjPSiHDfiQgMugs4R8p/yO0B0vqOjgh9LHZFf3NsD/fD4hqDb1+ZbOARplWn5v9Yfc7j
	Yihoty0dnUUSTHP5jUBr0XehfIxOpS+2XEFDD7I4ThzxmybghtAXs6cD1oCHXbt/uPHA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] docs: enhance xenstore.txt with permissions description
Message-Id: <E1optBb-000350-Az@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:28:19 +0000

commit bc3921135cf8590d0f587f460be431922183c4c4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d084d2c6dff7044956ebdf83a259ad6081a1d921)
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index a7d006519a..eccd596ee3 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:28:30 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:28:30 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434825.687434 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBm-00076y-MY; Tue, 01 Nov 2022 15:28:30 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434825.687434; Tue, 01 Nov 2022 15:28:30 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBm-00076q-JK; Tue, 01 Nov 2022 15:28:30 +0000
Received: by outflank-mailman (input) for mailman id 434825;
 Tue, 01 Nov 2022 15:28:29 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBl-00076i-FO
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:29 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBl-0001EI-Eb
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:29 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBl-00035T-Dx
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:29 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=7n+12qt4O7+ElXFhKawlMLcnzOzVnPR1L0uGkmndfU0=; b=go0VBOi2in174Oj0V1cBOurBMn
	util7DD0UHICnZXur1bXZuEApZjhCf5KvAniMdvlguHuWcwEP7YulZtl7imDzl7EgdiQl7hLZwmZZ
	A8r50syxYBRptg+bgINDk6K5gxmMLsehfP4immCIP9/i4DyrHqOMJrXOWtHwckITSGnE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1optBl-00035T-Dx@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:28:29 +0000

commit b9ede0950b3a6526d5ccea074841f093e0580948
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit db471408edd46af403b8bd44d180a928ad7fbb80)
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 20e67b1427..70f0c83de4 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -87,10 +87,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; SymbolMap.iter (fun _ -> recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid _ node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = SymbolMap.map walk node.children }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			SymbolMap.map walk node.children |> SymbolMap.filter is_valid } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -444,11 +455,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:28:40 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:28:40 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434826.687438 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBw-00079P-NZ; Tue, 01 Nov 2022 15:28:40 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434826.687438; Tue, 01 Nov 2022 15:28:40 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optBw-00079G-Kl; Tue, 01 Nov 2022 15:28:40 +0000
Received: by outflank-mailman (input) for mailman id 434826;
 Tue, 01 Nov 2022 15:28:39 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBv-000796-K8
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:39 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBv-0001Eu-JR
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:39 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optBv-000360-Gt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:39 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=E9sK8EynAwWq4T7S+yyKiWPHNpD8uZRxNdJ8CC+4nTQ=; b=JGZjeBQKuq6rH+ycUGJl3GtISI
	HT6YWl2G55/fCvDLrPTDLtmxl6KpoSgEVDDtlQkW36hVSondzZ065j9ug9Vivwt9gDJUD3Xie5XTL
	OWsZlizd8CQC98lfRHOuiD9y+6TLF5RVsploG5W8kw2e+ODnInV8mL/Bk5JWOTtGRKtI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1optBv-000360-Gt@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:28:39 +0000

commit d3649d33e1eae49d3925ef34a7ccf39cae8852e6
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3)
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index ce39ce28b5..6cb990ee7f 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -722,7 +722,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:28:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:28:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434827.687441 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optC6-0007CJ-Ov; Tue, 01 Nov 2022 15:28:50 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434827.687441; Tue, 01 Nov 2022 15:28:50 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optC6-0007CB-MK; Tue, 01 Nov 2022 15:28:50 +0000
Received: by outflank-mailman (input) for mailman id 434827;
 Tue, 01 Nov 2022 15:28:49 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optC5-0007Bu-N4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:49 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optC5-0001FB-ML
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:49 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optC5-00036R-Lj
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:49 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sxtza3sAPD50r6yZkgqQTKjWOHkiBUPk5g3BYZmWs9s=; b=mIgsvs9hI2sVUEBlsXVnv0T8rt
	P6Qt8irUfxDWb2ydQpJRnd1WggroXDzW292ZA4u0oGtsJ/Mt45wInfJK2X9nds7wPwC96Ai7dFVuK
	Ua6EdnIBPVtJDcbRDagvnfskBiwl+JWMKbLH5QVAYAdLAdeIoVqskBGMLLc7iVoeSY6E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: fix deleting node in transaction
Message-Id: <E1optC5-00036R-Lj@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:28:49 +0000

commit 2d3476effe3a9236867562f14dc26979a6527080
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187)
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 3e3eb47326..7ffe21bb52 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -418,7 +418,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:29:00 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:29:00 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434831.687473 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCG-0007sN-PY; Tue, 01 Nov 2022 15:29:00 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434831.687473; Tue, 01 Nov 2022 15:29:00 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCG-0007rh-KZ; Tue, 01 Nov 2022 15:29:00 +0000
Received: by outflank-mailman (input) for mailman id 434831;
 Tue, 01 Nov 2022 15:28:59 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCF-0007o3-QE
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:59 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCF-0001FU-PW
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:59 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCF-00038N-Oc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:28:59 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=zP3Q20aKANHtoVBqvXJKOkkXSG5ix+by51u+CIfugIY=; b=cemIuBQ6d4UM3s/zf0XBsX5jpf
	083uzO11g9pDBgBapJ5lEMlJnOkgJ5J382DuPUYg60qLPeyArcz0UuhmfiCb9P9nO3spiFnOuUXx9
	RE+Man58j+ONOGE7g4TKUJdBuxrUVLD88YgQdRF1Uf5ofkzQzlqNpPvCoaZW25RKa86Y=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.15] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1optCF-00038N-Oc@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:28:59 +0000

commit e818f4f0dabf83a6138cd77d7464495fab7bfc16
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff)
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9ddbd934f7..3c008c8cd4 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -692,8 +692,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -811,10 +810,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 7ffe21bb52..ac854197ca 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -199,25 +200,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -240,7 +236,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -259,10 +254,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -273,9 +264,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -302,7 +294,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -321,7 +313,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -333,7 +325,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -371,100 +362,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -556,6 +537,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -579,13 +561,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -660,7 +646,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -672,11 +658,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.15


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:29:12 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:29:12 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434834.687504 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCS-0000SS-CG; Tue, 01 Nov 2022 15:29:12 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434834.687504; Tue, 01 Nov 2022 15:29:12 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCS-0000RE-7o; Tue, 01 Nov 2022 15:29:12 +0000
Received: by outflank-mailman (input) for mailman id 434834;
 Tue, 01 Nov 2022 15:29:10 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCQ-00008W-Js
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:10 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCQ-0001Fw-JC
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:10 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCQ-0003EK-IQ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:10 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=2nqRluKAvvDs7yvPbKc7wW3UUPjuwEjwGnmNfzgBh+w=; b=QQZx22aHNT847adkCVo6Fn+hBc
	HQhH6tE2z1aUgKh6f8HRqx5l69dQf/qFXrd324sL8p+Y9dbQxQqor6iJcD6P1irBH/qAjAr5BhVtI
	hheI1PekqeUnfzc++KbnLgFroEsjisVnc+lDkqR6j5YIC8Vvwyf1sW4KL1Nv1KjB8UTE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1optCQ-0003EK-IQ@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:29:10 +0000

commit d0dd461bfc8dd25b94dcf72bc5f79a4b362e7f03
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 1cd3cc7ea27cda7640a8d895e09617b61c265697)
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 1d05d25a48..6afe8cb59d 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -977,9 +977,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -990,7 +989,7 @@ static int destroy_node(void *_node)
 
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -999,7 +998,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1021,23 +1021,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:29:21 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:29:21 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434840.687519 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCb-0001QX-UM; Tue, 01 Nov 2022 15:29:21 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434840.687519; Tue, 01 Nov 2022 15:29:21 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCb-0001PX-Qa; Tue, 01 Nov 2022 15:29:21 +0000
Received: by outflank-mailman (input) for mailman id 434840;
 Tue, 01 Nov 2022 15:29:20 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCa-0001Ij-Mr
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:20 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCa-0001G4-M9
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:20 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCa-0003Ep-LY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:20 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=id4jINrgu9v0d3O2JFI4npJ0IA8sCSSgnEHstUsQMdA=; b=Ou/6fDGHBYvlZ8LMzlZzrog85J
	YycRCOXk7IY8QTYtCIsLqBuvwaQ42XgjSYOd71IFqn0wVwTGKxOHlAkm9XQJsJkI3SQi+RKeBeGy3
	NanuPweEoLVzrv26urYyQlZAQZKThs781kxSbA/fuA/OP9XNTW1r8X6aE/ep1S9/qf3g=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1optCa-0003Ep-LY@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:29:20 +0000

commit bd50953ef300049cc2d20fdc5a34b90a97b6abc0
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34)
---
 tools/xenstore/xenstored_core.c        | 25 +++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 6afe8cb59d..8e91b55498 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -468,15 +468,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
@@ -979,18 +981,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	key.dptr = (void *)node->name;
-	key.dsize = strlen(node->name);
-
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 196a6fd2b0..9369c4cbfd 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -119,6 +119,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 2881f3b2e4..4ffa183111 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -582,6 +582,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:29:32 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:29:32 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434847.687535 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCm-0002Cz-9f; Tue, 01 Nov 2022 15:29:32 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434847.687535; Tue, 01 Nov 2022 15:29:32 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCm-0002Cs-6z; Tue, 01 Nov 2022 15:29:32 +0000
Received: by outflank-mailman (input) for mailman id 434847;
 Tue, 01 Nov 2022 15:29:30 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCk-00028p-Pt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:30 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCk-0001G8-PJ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:30 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCk-0003FE-OX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:30 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=oV1HtdiEEAVASZBFKVPP6sF2gQww9TtsMUZQDynIz3s=; b=RnZ/cWWQpkyeX/WKHQ9IVpPLN0
	/sqe7y+yvC/XQj0iBbQPv42bcwY9x2JsB/JZq+GrCLBtixI3wog5bccOaCFn0M19uaJs/LcOOns1p
	jqkhj4DtH7z24XqP+PTA3la6ahH1O1FVXTcAHaPyKn5lV4l2+FswsHOEZPhQkMjQUPhw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: split up send_reply()
Message-Id: <E1optCk-0003FE-OX@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:29:30 +0000

commit 00240cfc5e33b762850dfe16be501341b1fc5ca1
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32)
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 42 +++++++----------------
 3 files changed, 58 insertions(+), 59 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8e91b55498..e6776bae8f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -674,49 +674,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -724,8 +707,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 9369c4cbfd..2b0f796d9b 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -150,6 +150,7 @@ unsigned int get_strings(struct buffered_data *data,
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 9ff20690c0..6d8097376e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -72,37 +72,17 @@ static bool is_child(const char *child, const char *parent)
 	return child[len] == '/' || child[len] == '\0';
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
+static const char *get_watch_path(const struct watch *watch, const char *name)
 {
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
+	const char *path = name;
 
 	if (watch->relative_path) {
-		name += strlen(watch->relative_path);
-		if (*name == '/') /* Could be "" */
-			name++;
+		path += strlen(watch->relative_path);
+		if (*path == '/') /* Could be "" */
+			path++;
 	}
 
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
+	return path;
 }
 
 /*
@@ -181,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -252,7 +236,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:29:42 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:29:42 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434852.687550 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCw-0002ra-MC; Tue, 01 Nov 2022 15:29:42 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434852.687550; Tue, 01 Nov 2022 15:29:42 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optCw-0002rS-J2; Tue, 01 Nov 2022 15:29:42 +0000
Received: by outflank-mailman (input) for mailman id 434852;
 Tue, 01 Nov 2022 15:29:40 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCu-0002nW-TV
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:40 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCu-0001GV-SQ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:40 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optCu-0003G2-Rd
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:40 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=KjvVXzDD62gePX7Ry6mFEoQF1Tzpf9/0eBu6oyhV8z0=; b=xAu0itHJIcSu+N7ec7jYY03sBi
	oaW4f4IzM19u2EKXVH9hs4HaRuhOxJ4e0NDfsvVsFR8FvQalPXyeRnXRyHCjW+tp1pbSGfN3vYKs1
	2Jhs1DSx1aSamVJ1iUxyWi6ZMwgJti3KC2vK+oqPbUTwohcmV96yKy49xJAvDnQc4OdI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1optCu-0003G2-Rd@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:29:40 +0000

commit 3530aa6aca01fdffdc9e4af18d4278d169458e60
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ead062a68a9c201a95488e84750a70a107f7b317)
---
 tools/xenstore/xenstored_core.c   | 26 +++++++++++++++++---------
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c |  7 +------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e6776bae8f..5d54779d40 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -208,6 +208,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -251,8 +266,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
@@ -1391,18 +1405,12 @@ static struct {
  */
 static void ignore_connection(struct connection *conn)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored\n", conn);
 
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2b0f796d9b..83d49693fc 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -226,6 +226,8 @@ extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
 
+void conn_free_buffered_data(struct connection *conn);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index d5e1e3e9d4..3bff322d02 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -402,15 +402,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:29:52 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:29:52 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434853.687554 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optD6-0003C7-Nj; Tue, 01 Nov 2022 15:29:52 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434853.687554; Tue, 01 Nov 2022 15:29:52 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optD6-0003By-Kj; Tue, 01 Nov 2022 15:29:52 +0000
Received: by outflank-mailman (input) for mailman id 434853;
 Tue, 01 Nov 2022 15:29:51 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optD4-00039f-W2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:50 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optD4-0001GZ-VJ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:50 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optD4-0003GZ-Ug
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:29:50 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=JpFPGp6TjLi1Tt7u6lcd+NiAp8sFjDU4Dkin/SJGRC4=; b=kbpb0lxhbN+r0cYhI/GvZQQiuy
	UG4RzAV0LRHhCYpYEQ/lJpQZxaZp7mAPUoTTPo44oRmx2q8h+fc8l1JQmZ0sZv8+qPY6f6PNCcZJq
	WBWkf796yVO09VNJRJ2eNvICpH7i0dXSM7EuwHMU4Evc3J8BtV5nqvLR1ZZ4R2OgixSw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: reduce number of watch events
Message-Id: <E1optD4-0003GZ-Ug@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:29:50 +0000

commit a03e2a386e3db9c2df6e24bfd3a44f52f09ca8a5
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297)
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5d54779d40..53d003aebf 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1182,7 +1182,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1194,7 +1194,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1206,7 +1206,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1232,13 +1237,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 4ffa183111..6fbdb29dcd 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -329,6 +333,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -383,15 +410,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 6d8097376e..2f9367767e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:30:02 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:30:02 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434854.687559 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDG-0003ZH-RT; Tue, 01 Nov 2022 15:30:02 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434854.687559; Tue, 01 Nov 2022 15:30:02 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDG-0003Yu-Ny; Tue, 01 Nov 2022 15:30:02 +0000
Received: by outflank-mailman (input) for mailman id 434854;
 Tue, 01 Nov 2022 15:30:01 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDF-0003JP-2g
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:01 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDF-0001Gd-25
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDF-0003HR-1N
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=hTs+sjV2mR1dWuctOVsA/DIXlIbD3mHLu/0xFbt3BpQ=; b=c0L008hhE07dCyOhFE7melrXN8
	r9whtyC74rj5ijgmsoQ0CrVNPCuTLol9wEv3x9Wl6BWGEfZcwa5SYDMQOvtIJbe7PVqG0VkntFG0+
	74ORh+3SZ8P2vHI+d56X6yB+0714xtp/TiW0c4xM2kTczB9EnSLsOD/YFlAfqyhcCKCc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: let unread watch events time out
Message-Id: <E1optDF-0003HR-1N@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:30:01 +0000

commit 36ed7fe5da0eb8554e94718fb6599795cdef21d0
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 5285dcb1a5c01695c11e6397c95d906b5e765c98)
---
 tools/xenstore/xenstored_core.c | 127 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 53d003aebf..98837ef2e9 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -106,6 +106,8 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -208,19 +210,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -333,6 +408,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *p_ro_sock_pollfd_idx,
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -354,10 +430,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *p_ro_sock_pollfd_idx,
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (domain_can_read(conn) ||
 			    (domain_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -701,6 +779,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -752,6 +831,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -1994,6 +2079,9 @@ static void usage(void)
 "  -W, --watch-nb <nb>     limit the number of watches per domain,\n"
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2015,6 +2103,7 @@ static struct option options[] = {
 	{ "trace-file", 1, NULL, 'T' },
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2026,6 +2115,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2037,7 +2159,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2082,6 +2204,9 @@ int main(int argc, char *argv[])
 		case 'A':
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 83d49693fc..3112c11811 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <dirent.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -56,6 +57,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -88,6 +91,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -199,6 +203,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:30:12 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:30:12 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434855.687562 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDQ-0004EV-St; Tue, 01 Nov 2022 15:30:12 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434855.687562; Tue, 01 Nov 2022 15:30:12 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDQ-0004EN-Pl; Tue, 01 Nov 2022 15:30:12 +0000
Received: by outflank-mailman (input) for mailman id 434855;
 Tue, 01 Nov 2022 15:30:11 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDP-0004Dh-5p
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:11 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDP-0001H7-5C
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:11 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDP-0003IF-4X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:11 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=rmBE8tlHd2Fi2VvaItxZih2tz4v7LjAhcL6GP8twovU=; b=Cz/sEk+kNjhbbs1+DCWTus8O2D
	B8RKkRSJ/t3Xf+YjxNXABbu7aGvtQC8cCftPOtxRDHvAmFLAGMiKu3MkRiJDJWLfHNjtyDTfHOUth
	lfIO5EXZNHK6xWGieWwYaEYdPqyGRY7Jg49C+2g6RQanhfCmtEdgl2RfeHYjJCyfwk/Q=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: limit outstanding requests
Message-Id: <E1optDP-0003IF-4X@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:30:11 +0000

commit 3dafa5a77440325a51dfbd75a297febc618bb24a
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 36de433a273f55d614c83b89c9a8972287a1e475)
---
 tools/xenstore/xenstored_core.c   | 78 ++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h   | 20 +++++++++-
 tools/xenstore/xenstored_domain.c | 37 ++++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 ++++++--
 5 files changed, 141 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 98837ef2e9..2ed91d1329 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -105,6 +105,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -220,12 +221,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -241,6 +254,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -349,6 +386,7 @@ static bool write_messages(struct connection *conn)
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -362,6 +400,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -800,6 +843,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -807,7 +852,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -837,8 +883,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1574,6 +1625,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1644,6 +1696,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
 	new->is_ignored = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 
@@ -2079,6 +2132,9 @@ static void usage(void)
 "  -W, --watch-nb <nb>     limit the number of watches per domain,\n"
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2103,6 +2159,7 @@ static struct option options[] = {
 	{ "trace-file", 1, NULL, 'T' },
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2148,6 +2205,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2159,7 +2230,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2204,6 +2275,9 @@ int main(int argc, char *argv[])
 		case 'A':
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 3112c11811..edeaa96dd1 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -45,6 +45,8 @@ typedef int32_t wrl_creditt;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -52,6 +54,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -93,6 +106,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -154,7 +170,8 @@ unsigned int get_strings(struct buffered_data *data,
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -202,6 +219,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3bff322d02..2dd80eb1a7 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -82,6 +82,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -284,8 +287,12 @@ bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	if (conn->is_ignored)
 		return false;
@@ -334,7 +341,7 @@ static struct domain *alloc_domain(void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -383,8 +390,6 @@ static int new_domain(struct domain *domain, int port)
 	domain->conn->id = domain->domid;
 
 	domain->remote_port = port;
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
 
 	return 0;
 }
@@ -922,6 +927,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5e00087206..4bff2e655b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -67,6 +67,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 2f9367767e..c50c0575f0 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -238,8 +241,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	talloc_set_destructor(watch, destroy_watch);
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:30:22 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:30:22 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434856.687565 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDa-0004I6-UE; Tue, 01 Nov 2022 15:30:22 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434856.687565; Tue, 01 Nov 2022 15:30:22 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDa-0004Hy-RK; Tue, 01 Nov 2022 15:30:22 +0000
Received: by outflank-mailman (input) for mailman id 434856;
 Tue, 01 Nov 2022 15:30:21 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDZ-0004HV-9E
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:21 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDZ-0001HC-8Z
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:21 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDZ-0003Ik-7h
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:21 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=BMa4Xj0EikqGR968ecu9cbksHFdzQgc6dp17BGWHyVc=; b=wsil2Ec636IDY7j7o7/6ARwX4S
	mecPB1iR/YMmByRDAs0k+B61yvsk7myBLImL5B9QyrL3ad7P7WMzDpfU2NRoJBqoH4lZ286l+tmjy
	kaiXxTzdGGQtVEdAQM5ov30ef/jquHtY6PjGzUl1GgoODFKQuzfi5PnDpnZBJDflu0Mk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1optDZ-0003Ik-7h@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:30:21 +0000

commit 83b9da9282488bfadaf322a592805b4421d9b60b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2)
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2ed91d1329..c6f1d4189c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -823,6 +823,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -855,7 +856,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -877,12 +878,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index edeaa96dd1..1eb6131fc8 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -51,6 +51,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:30:32 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:30:32 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434857.687569 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDk-0004Lv-1g; Tue, 01 Nov 2022 15:30:32 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434857.687569; Tue, 01 Nov 2022 15:30:32 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDj-0004Lm-V7; Tue, 01 Nov 2022 15:30:31 +0000
Received: by outflank-mailman (input) for mailman id 434857;
 Tue, 01 Nov 2022 15:30:31 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDj-0004Lb-CN
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:31 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDj-0001HG-Bi
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:31 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDj-0003J9-Ay
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:31 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=CW6mRzfm+Cj9IwaOuOw2z1QEdaUfshO0KvrUGrg2z/Y=; b=gV3sYDRBOwB9nK0b9nUhTjMwoC
	voIhzcWlMxc2bRrQifR+anpp8diLVtqgkKWt/1UPR1RkOGcKl6p9IunGxu/F7C4ByQGBbzez1jP4D
	RrScrtIX+Z0SN7gkZXOj4OwzbQptIQAzlWahorVHga9gQgDPVjnhViQTGacwOj4Mr3RU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: fix connection->id usage
Message-Id: <E1optDj-0003J9-Ay@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:30:31 +0000

commit 9ad9fde555b6ec98c2cec05e28d3ee4c3127d6f5
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831)
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 8d48ab4820..bce6662f6e 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -198,7 +198,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	int cmd;
 	char **vec;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	num = xs_count_strings(in->buffer, in->used);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1eb6131fc8..98db4afcaa 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -93,7 +93,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this a read-only connection? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6fbdb29dcd..9bef6e72a5 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -483,7 +483,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:30:42 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:30:42 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434858.687574 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDu-0004QR-3L; Tue, 01 Nov 2022 15:30:42 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434858.687574; Tue, 01 Nov 2022 15:30:42 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optDu-0004QG-0O; Tue, 01 Nov 2022 15:30:42 +0000
Received: by outflank-mailman (input) for mailman id 434858;
 Tue, 01 Nov 2022 15:30:41 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDt-0004Q0-Fu
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:41 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDt-0001Hc-FF
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:41 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optDt-0003Jd-EC
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:41 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=RwNmyi/Jy76URvADwQwmaZ16P+bblkx1hMAvwBPqgsc=; b=2rzQScxKiu4Id5WXw68fcYGhcS
	brqJEKodvHPElN+y3m3dUs4djr3Ecw+jVrZa0lgwc3ecnZlfMajFjERgPM0mYMqu9/+e4sopJ7pd9
	ERD12YH8ZHTlDAG2lSX8dP+6nT1FitZETXJt7ZNj4xEXZQ2rh3tocXQAtIAJqNGeo9dY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1optDt-0003Jd-EC@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:30:41 +0000

commit 82dfb67578243a1abda3774df0dfd511bdff0572
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit dbef1f7482894c572d90cd73d99ed689c891e863)
---
 tools/xenstore/xenstored_control.c     |   1 +
 tools/xenstore/xenstored_core.c        |  39 +++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 5 files changed, 107 insertions(+), 50 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index bce6662f6e..ab0794deed 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -25,6 +25,7 @@
 #include "talloc.h"
 #include "xenstored_core.h"
 #include "xenstored_control.h"
+#include "xenstored_domain.h"
 
 struct cmd_s {
 	char *cmd;
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c6f1d4189c..12d013d249 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -545,7 +545,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -567,7 +567,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1161,13 +1161,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1217,8 +1221,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1499,10 +1507,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
 
-	if (write_node(conn, node, false))
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
+
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 2dd80eb1a7..306e12358b 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -358,6 +359,18 @@ static struct domain *alloc_domain(void *context, unsigned int domid)
 	return domain;
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port)
 {
 	int rc;
@@ -767,30 +780,28 @@ void domain_init(void)
 	virq_port = rc;
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -826,7 +837,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -836,8 +847,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -856,25 +873,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -884,13 +901,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4bff2e655b..4edf1dba94 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -57,10 +57,10 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 9bef6e72a5..bf2fda8234 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -523,8 +523,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:30:52 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:30:52 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434859.687577 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optE4-0004Wh-5A; Tue, 01 Nov 2022 15:30:52 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434859.687577; Tue, 01 Nov 2022 15:30:52 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optE4-0004WZ-2G; Tue, 01 Nov 2022 15:30:52 +0000
Received: by outflank-mailman (input) for mailman id 434859;
 Tue, 01 Nov 2022 15:30:51 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optE3-0004WH-Ij
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:51 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optE3-0001Hg-I5
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:51 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optE3-0003KQ-HY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:30:51 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=UxxhYvdFwm5G/ohsJLaKO884XP8+xqQewNHxdfpBak4=; b=5fEusaNdPoXycdK7zTtu9LwOKS
	9+LPjXZVNTVivR6mVPrSnMcI7Hw0AUlz4yaXrpWRGKll+o9/Bf5CE7eleTbI4UuG3r0doOn6Z1hmw
	h+OtkZtsdFhDFEcQ/limHvi6yEdIlELLyfo6+dTM9e+C8pnWQr2AwEqLEUzwWY9e67lc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1optE3-0003KQ-HY@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:30:51 +0000

commit 93a9c3a066193e21763c84e04fbe56902bcb5c07
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 268369d8e322d227a74a899009c5748d7b0ea142)
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index cc7dfc8c64..34db3b7847 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -59,4 +59,8 @@
     })
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 12d013d249..ff649b7544 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -105,6 +105,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
@@ -502,6 +503,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -523,14 +525,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -545,19 +546,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -672,7 +690,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -735,7 +753,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1117,7 +1135,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1396,7 +1414,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1424,7 +1442,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2177,6 +2195,8 @@ static void usage(void)
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2258,6 +2278,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 98db4afcaa..7e371253d2 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -34,6 +34,7 @@
 #include "list.h"
 #include "tdb.h"
 #include "hashtable.h"
+#include "utils.h"
 
 /* DEFAULT_BUFFER_SIZE should be large enough for each errno string. */
 #define DEFAULT_BUFFER_SIZE 16
@@ -223,6 +224,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index bf2fda8234..778b7e439c 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -266,6 +269,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -303,6 +311,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:31:02 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:31:02 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434860.687582 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEE-0004dZ-7A; Tue, 01 Nov 2022 15:31:02 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434860.687582; Tue, 01 Nov 2022 15:31:02 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEE-0004dR-3u; Tue, 01 Nov 2022 15:31:02 +0000
Received: by outflank-mailman (input) for mailman id 434860;
 Tue, 01 Nov 2022 15:31:01 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optED-0004dD-Lq
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:01 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optED-0001Hk-LE
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optED-0003LK-KS
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=AS8qOoUKhBcIMYKS+OmaSRYvOmn/GVNaEXqdep70NZ4=; b=2JB/rVeBP/ta20mpXN3+P/ai0v
	oEwTb5gPuj/04ESWYun6m9ehtxAVkmQsoGnLRqRM1owjUQtxtBzWDIoFRVRrBCHNPGCgjozTzKB2w
	LCrMHyBLRVEkXK37c8YYwF0C1Y4Kp8ESkE+pqEvz71Tdilp/fgbOQC9Xr8dVAQ2k4ZWs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1optED-0003LK-KS@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:31:01 +0000

commit 0406917f364d170eae6e25ab3e9314e27db2c790
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 60e2f6020dea7f616857b8fc1141b1c085d88761)
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 2 ++
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ff649b7544..8123a65a58 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1834,7 +1834,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -1873,7 +1874,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(void)
+void setup_structure(void)
 {
 	char *tdbname;
 	tdbname = talloc_strdup(talloc_autofree_context(), xs_daemon_tdb());
@@ -1891,6 +1892,7 @@ static void setup_structure(void)
 	manual_node("/", "tool");
 	manual_node("/tool", "xenstored");
 	manual_node("/tool/xenstored", NULL);
+	domain_entry_fix(dom0_domid, 3, true);
 
 	check_store();
 }
@@ -2389,9 +2391,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure();
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init)
 		domain_init();
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 7e371253d2..d95e4262a9 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -195,6 +195,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(void);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 void check_store(void);
 void corrupt(struct connection *conn, const char *fmt, ...);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 306e12358b..bed6c4e05a 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -732,6 +732,8 @@ static int dom0_init(void)
 	if (dom0->interface == NULL)
 		return -1;
 
+	setup_structure();
+
 	talloc_steal(dom0->conn, dom0); 
 
 	xenevtchn_notify(xce_handle, dom0->port);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:31:12 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:31:12 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434861.687586 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEO-0004iN-AY; Tue, 01 Nov 2022 15:31:12 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434861.687586; Tue, 01 Nov 2022 15:31:12 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEO-0004iD-7M; Tue, 01 Nov 2022 15:31:12 +0000
Received: by outflank-mailman (input) for mailman id 434861;
 Tue, 01 Nov 2022 15:31:11 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEN-0004i3-Om
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:11 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEN-0001I4-O7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:11 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEN-0003Lx-Nc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:11 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Mch3y/PwZcq4mkT7mFAsshW3UyRrvwOfE45qzfAUVCs=; b=2nv++2j/qGfY+72SiDGuCPqB9h
	rD8P/+Wya6+0aC9VqacWVD0vrnYP4VOoFVlUZT1xkdjwCjsiBH6BzjCs+9njcsgG2MwLWpc1ItwG6
	eMQ7qIRHovupyPdEXBsUNRuugPf2++Kn9fHznufS4yWbzQSQQYsDvwJOIDu1HmGr2jk8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1optEN-0003Lx-Nc@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:31:11 +0000

commit 03889b67169cf973c0e0008a22c5b7cd119f90e9
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d4a8ec7a93faedbe54fd197db146de628459e77)
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8123a65a58..9fd83ea025 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -107,6 +107,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2199,7 +2201,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2225,6 +2234,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2270,7 +2280,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2278,11 +2288,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2297,7 +2312,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2343,7 +2358,10 @@ int main(int argc, char *argv[])
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index d95e4262a9..4e53072e63 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -226,6 +226,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index bed6c4e05a..8daa876588 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -80,6 +80,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -293,6 +300,9 @@ bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	if (conn->is_ignored)
@@ -934,6 +944,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4edf1dba94..3a8c6bab48 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,6 +64,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:31:22 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:31:22 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434862.687590 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEY-0004me-Bh; Tue, 01 Nov 2022 15:31:22 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434862.687590; Tue, 01 Nov 2022 15:31:22 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEY-0004mW-91; Tue, 01 Nov 2022 15:31:22 +0000
Received: by outflank-mailman (input) for mailman id 434862;
 Tue, 01 Nov 2022 15:31:21 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEX-0004mG-RY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:21 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEX-0001IB-Qt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:21 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEX-0003MM-QJ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:21 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Wyj7M8BQ4IYlKO9hnBw7dsn7XK0iR93svtcPG5n3nT4=; b=A5WN/v/nEVdez43DojecFXYP2q
	BLC/Du73/WgdHoCT3txQ5S8guGOlQwY1jtebDwHbScc6COupn8DpVi/YOkB1TN1Zy/BTf/hCdrkl8
	W4/uzHMLdJYGEZEosMMnWtdDTzqhvkwUfsc82SGQtdQdKKnBAFRp6zC/abcwusa+4sDk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: add memory accounting for responses
Message-Id: <E1optEX-0003MM-QJ@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:31:21 +0000

commit cc289061d93786aa5bd504c91b583e1abb55bbb4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    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 f6d00133643a524d2138c9e3f192bbde719050ba)
---
 tools/xenstore/xenstored_core.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9fd83ea025..4322d3cf63 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -257,6 +257,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -845,11 +847,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -914,6 +919,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:31:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:31:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434863.687594 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEj-0004qm-DG; Tue, 01 Nov 2022 15:31:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434863.687594; Tue, 01 Nov 2022 15:31:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEj-0004qe-AX; Tue, 01 Nov 2022 15:31:33 +0000
Received: by outflank-mailman (input) for mailman id 434863;
 Tue, 01 Nov 2022 15:31:31 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEh-0004q9-UQ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:31 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEh-0001IJ-Ti
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:31 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEh-0003Mw-T7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:31 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Kz78JpMhiOeLwmoUrkQqq8JRR3kO7iSiMvzEeu5/VCI=; b=Kk284SdfBmRwNBn9FvQvKeM09v
	UcRmlUkiTao9ZH+QZZpHNZPQeA/hEcL6c4l+//1KMjGU/BXK5WYYGAiShTxsymLeJWkLCW1SwmwFq
	ZSzaRnqAkd3dIxHoN2T9QbXi1dOWANW9gScn5nLExQl+JD7BKJlQQA9xJPTvoYJs668E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: add memory accounting for watches
Message-Id: <E1optEh-0003Mw-T7@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:31:31 +0000

commit 3a7c46a94454aa48f6e247ed91773d96b4b70afb
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    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 7f9978a2cc37aaffab2fb09593bc598c0712a69b)
---
 tools/xenstore/xenstored_core.c  | 1 +
 tools/xenstore/xenstored_watch.c | 7 ++++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 4322d3cf63..0f589a1f63 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -407,6 +407,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index c50c0575f0..7118c30e8c 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -224,7 +224,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 		return ENOMEM;
 	watch->node = talloc_strdup(watch, vec[0]);
 	watch->token = talloc_strdup(watch, vec[1]);
-	if (!watch->node || !watch->token) {
+	if (!watch->node || !watch->token ||
+	    domain_memory_add_chk(conn->id, strlen(vec[0]) + strlen(vec[1]))) {
 		talloc_free(watch);
 		return ENOMEM;
 	}
@@ -265,6 +266,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -280,6 +283,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:31:43 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:31:43 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434864.687598 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEt-0004u2-F3; Tue, 01 Nov 2022 15:31:43 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434864.687598; Tue, 01 Nov 2022 15:31:43 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optEt-0004tu-C4; Tue, 01 Nov 2022 15:31:43 +0000
Received: by outflank-mailman (input) for mailman id 434864;
 Tue, 01 Nov 2022 15:31:42 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEs-0004tg-1V
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEs-0001KD-0p
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optEs-0003NO-0E
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=7hKXj9+hOWwhM0C2hFD3KvwZmWItcIbdFavYhQFlK3g=; b=zdMyz+rAW5woeK79ScmMRWH4Yu
	qg0nBlMaLQ3zdAR/7tsUg4ckUsBnvHECTFhUd4Cp6/Ziu1citrSx8R/h5ff8ihpdT2diiZk3+AwKR
	UmSe2dr3lRoQXYuap7SKeaRUyWTVzRFRJx7Wa2702vi9HINusrsLzzUnf6pbU4fmEXLs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: add memory accounting for nodes
Message-Id: <E1optEs-0003NO-0E@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:31:42 +0000

commit 36812ae518975e2eb40ad14ff0c70dd0ab08bf82
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    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        | 139 ++++++++++++++++++++++++++++++---
 tools/xenstore/xenstored_core.h        |  13 +++
 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 0f589a1f63..6ed1ae2614 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -498,6 +498,117 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *p_ro_sock_pollfd_idx,
 	}
 }
 
+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.
@@ -551,9 +662,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. */
@@ -617,12 +734,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;
 }
 
@@ -1121,7 +1235,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;
 	}
@@ -1184,6 +1298,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;
 
@@ -1192,17 +1307,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);
 
 	/*
@@ -1254,7 +1369,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;
 			}
 		}
@@ -2077,7 +2192,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);
 		}
 	}
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 4e53072e63..521bc80384 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -141,6 +141,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 */
@@ -163,6 +168,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. */
@@ -258,6 +266,11 @@ extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
 
+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);
 
 #endif /* _XENSTORED_CORE_H */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 778b7e439c..c1beb40a3d 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;
 
@@ -292,6 +295,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
@@ -416,11 +421,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;
@@ -431,7 +436,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);
@@ -459,7 +464,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);
@@ -503,6 +508,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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:31:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:31:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434865.687602 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optF3-0004yb-Hu; Tue, 01 Nov 2022 15:31:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434865.687602; Tue, 01 Nov 2022 15:31:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optF3-0004yT-FC; Tue, 01 Nov 2022 15:31:53 +0000
Received: by outflank-mailman (input) for mailman id 434865;
 Tue, 01 Nov 2022 15:31:52 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optF2-0004y9-4X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:52 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optF2-0001KH-3w
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:52 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optF2-0003O9-3A
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:31:52 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=XFxQ5kadweAyoLJ7sXDfKeN/ZpGCGVwLEeQiyqYmjwU=; b=OnHsNys9OClgRWfWKKCEcFzuq7
	ui3kzyVcZmz5MbukJpqtuEAogfEeQeXNg1g029JXaqn4pV7GdUPHiKVWVJsZL3OXsYV8E2oNMvC5Z
	Pr0pZcdTOH4UktLC2aBhmuPuUjx0sIn4stT+QUY51YvoxM1HFPEfnTwcfbAr3QNWTQh4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: add exports for quota variables
Message-Id: <E1optF2-0003O9-3A@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:31:52 +0000

commit 0cc9d66691d029d7df28da5464ab20c3ca299379
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 1da16d5990b5f7752657fca3e948f735177ea9ad)
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 521bc80384..5abf06c21c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -231,6 +231,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index c1beb40a3d..6e29118c80 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static void set_tdb_key(const char *name, TDB_DATA *key)
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 7118c30e8c..19d0fb01b1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:32:03 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:32:03 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434866.687606 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFD-00054R-Ji; Tue, 01 Nov 2022 15:32:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434866.687606; Tue, 01 Nov 2022 15:32:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFD-00054J-Gm; Tue, 01 Nov 2022 15:32:03 +0000
Received: by outflank-mailman (input) for mailman id 434866;
 Tue, 01 Nov 2022 15:32:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFC-00053s-7e
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFC-0001KY-71
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFC-0003Op-6O
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Jw35dt006mwQ/nwaW0uf10KmI1Za8aL41K3yW7gCKE4=; b=DcCQVhaAn4cCs6J6GSVr6Oek9z
	Bk2dm4zT5gnJkxgE/BX5DNXQ+bdbt0msYcRJMoUz1xpBUvo76YoI6WI3yx2/ecKgDcBqlWZBUnK9D
	QNAE5nkrCL3RFexTscEoNwFyA00EOi0rWTx5t1fW/wJM0kxZoBx6lLtGL3LXxsgKZyXA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1optFC-0003Op-6O@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:32:02 +0000

commit 7c5316d7c7b805a138c718138e81f7218da144c4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 2081f20f55..1f42a377c1 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -329,6 +329,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index ab0794deed..0227a55656 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "utils.h"
@@ -62,6 +63,114 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 #ifdef __MINIOS__
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
@@ -154,6 +263,8 @@ static struct cmd_s cmds[] = {
 	{ "memreport", do_control_memreport, "[<file>]" },
 #endif
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8daa876588..47e8010b34 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -348,6 +349,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 3a8c6bab48..e013a9991c 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -90,6 +90,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:32:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:32:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434867.687610 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFN-00058X-Kt; Tue, 01 Nov 2022 15:32:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434867.687610; Tue, 01 Nov 2022 15:32:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFN-00058P-II; Tue, 01 Nov 2022 15:32:13 +0000
Received: by outflank-mailman (input) for mailman id 434867;
 Tue, 01 Nov 2022 15:32:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFM-000582-CZ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFM-0001Kc-9s
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFM-0003PM-9G
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=4+QC82DGFvreJI8CsWIHVkHMT9SfHa5Gb9z0Sbx3RTE=; b=VjSgr/EMziqXL5Gd9OOvLaoa1m
	mCQi0vypnEQGc7Rj3ZBipkmliFf+eReSd7BSbpQ/dSnwX2wdZS7WgKeow9TEqHqzGl5jsaQeSsMuA
	u3Tx6GmpBKiLMAvUVSEGqqieM3oIcJNmBjk5baweDqfXGA5S6cShU9gho/z2sbPZE+nk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1optFM-0003PM-9G@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:32:12 +0000

commit 0bc44ec825866c0ef877f0e3bd158fc470191f90
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 84734955d4bf629ba459a74773afcde50a52236f)
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index f574397a4c..96c125a969 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -22,9 +22,9 @@ let xs_daemon_socket_ro = Paths.xen_run_stored ^ "/socket_ro"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:32:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:32:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434872.687615 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFX-0005C3-NM; Tue, 01 Nov 2022 15:32:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434872.687615; Tue, 01 Nov 2022 15:32:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFX-0005Bs-Jn; Tue, 01 Nov 2022 15:32:23 +0000
Received: by outflank-mailman (input) for mailman id 434872;
 Tue, 01 Nov 2022 15:32:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFW-0005Bh-DN
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFW-0001Kj-Ci
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFW-0003Pl-C4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=+/Dg55z56/GfJw2nykB8iq2gSzhVhP2qsroDZcV43Ww=; b=6lA+eacDjJPPQeSVdWpjBx9R5+
	Wuob7EADgipvwO3iT1jqoO2xK1bJpnIpKtgPpa7ewAJf/YcIijfxHnjiZ8eU2QFc3G7/BZ4ZkpBef
	tbuDUqS0kCJDgKYyWq+X3SOs+In0wuP/NchQ7F7OFJNaJUe0VJotc3ieVqrlovOdA88M=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1optFW-0003Pl-C4@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:32:22 +0000

commit f6a5a1d2e34c995a570c9477010c75f3b87a51cd
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    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 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff)
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 3ab09c6ce9..3279b19b1b 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:32:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:32:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434876.687618 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFh-0005FC-Oa; Tue, 01 Nov 2022 15:32:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434876.687618; Tue, 01 Nov 2022 15:32:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFh-0005F5-Ld; Tue, 01 Nov 2022 15:32:33 +0000
Received: by outflank-mailman (input) for mailman id 434876;
 Tue, 01 Nov 2022 15:32:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFg-0005Eq-GL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFg-0001Ks-Fg
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFg-0003QA-Ex
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=54xUQPEXM8+Dj1gtbCm6Q3wD70zZSj3fM2OSqZkRSPQ=; b=pPr4W/fE8KX3KERumyzkvVI4VU
	WzZZu1HnWuDoa8xX8287wseavaHh/9hnVOE+OklvkVq4HqedF8bZS7uHksauhl4Q5meH+om1v03Kc
	zz+HoQTcEbslKlBaUe0SxlRKc3IRovBMJRgkkC+A6+DDbiIi/KdIBoSgB4wz0xcn2L4Q=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml: GC parameter tuning
Message-Id: <E1optFg-0003QA-Ex@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:32:32 +0000

commit 276908c6c1bcf5ecc5c5bf0d4640c68b12bd3c35
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 4a8bacff20b857ca0d628ef5525877ade11f2a42)
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 96c125a969..1a5d2f34a6 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -26,6 +26,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 369b5036f4..0b6343dfc7 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -229,6 +230,67 @@ let to_file store cons file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -238,6 +300,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:32:43 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:32:43 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434877.687622 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFr-0005IW-Rh; Tue, 01 Nov 2022 15:32:43 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434877.687622; Tue, 01 Nov 2022 15:32:43 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optFr-0005IO-Ok; Tue, 01 Nov 2022 15:32:43 +0000
Received: by outflank-mailman (input) for mailman id 434877;
 Tue, 01 Nov 2022 15:32:42 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFq-0005I8-JF
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFq-0001LC-Ib
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optFq-0003QZ-Hv
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=3HDJyT9wLatQGV69NzzC0eiGhLsUL2KSq2o8wtlz4VA=; b=cqPAHsJiIJPC/+0h39PWBhmhIy
	I93/Sdh/c8SzZZYrbUdc65XkBOPizvQSMBFcvEYpdsC5C/onibqbcQ7SITENtzCAiEUOln0pZH+2y
	+GYnRanvwnOZDhrixL0GSAPR+EVVij01SwV6eM4onxZuRm3xHzHsC0n1qdqM+M/xq0rg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml/libs/xb: hide type of Xb.t
Message-Id: <E1optFq-0003QZ-Hv@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:32:42 +0000

commit 3a67865614eff0988332ed68876e7b9512a5453e
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Fri Jul 29 18:53:29 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml/libs/xb: hide type of Xb.t
    
    Hiding the type will make it easier to change the implementation
    in the future without breaking code that relies on it.
    
    No functional change.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba)
---
 tools/ocaml/libs/xb/xb.ml           | 3 +++
 tools/ocaml/libs/xb/xb.mli          | 9 ++-------
 tools/ocaml/xenstored/connection.ml | 4 +---
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 104d319d77..8404ddd8a6 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out
 let input_len con = Queue.length con.pkt_in
 let has_in_packet con = Queue.length con.pkt_in > 0
 let get_in_packet con = Queue.pop con.pkt_in
+let has_partial_input con = match con.partial_in with
+	| HaveHdr _ -> true
+	| NoHdr (n, _) -> n < Partial.header_size ()
 let has_more_input con =
 	match con.backend with
 	| Fd _         -> false
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 3a00da6cdd..794e35bb34 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,13 +66,7 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
-type t = {
-  backend : backend;
-  pkt_in : Packet.t Queue.t;
-  pkt_out : Packet.t Queue.t;
-  mutable partial_in : partial_buf;
-  mutable partial_out : string;
-}
+type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
 val queue : t -> Packet.t -> unit
@@ -97,6 +91,7 @@ val has_output : t -> bool
 val peek_output : t -> Packet.t
 val input_len : t -> int
 val has_in_packet : t -> bool
+val has_partial_input : t -> bool
 val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index daf8d804f7..70c4348552 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -125,9 +125,7 @@ let get_perm con =
 let set_target con target_domid =
 	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
 
-let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with
-	| Xenbus.Xb.Xenmmap _ -> true
-	| _ -> false
+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
 let send_reply con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:32:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:32:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434879.687625 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optG1-0005Lf-T5; Tue, 01 Nov 2022 15:32:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434879.687625; Tue, 01 Nov 2022 15:32:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optG1-0005LX-QH; Tue, 01 Nov 2022 15:32:53 +0000
Received: by outflank-mailman (input) for mailman id 434879;
 Tue, 01 Nov 2022 15:32:52 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optG0-0005LO-MX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:52 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optG0-0001LG-Lp
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:52 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optG0-0003Qy-L1
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:32:52 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=rEXYpRDr5q06KsuX6tFQik3+Oa5wzkicn0La/SQDeOw=; b=ZFW3rfAqvJqyJMGQseQdmeITxx
	b61AYkVqUZRue3bv6dBJ4jKL48Izkq7Fp2iCcnyQ4ZcMOYcobmFftS/yezM7sLCIIMRyIvFqRA09G
	2GBiH0pxAM+EZ6nq47BY6jpKTqZPIVNkicRekykQKKONBn1Jwn/guxcT50ySaYSC+LEY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1optG0-0003Qy-L1@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:32:52 +0000

commit 7f5d36df7c72f5f83a0027de45cb314c63f07f8f
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c0a86a462721008eca5ff733660de094d3c34bc7)
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  2 --
 tools/ocaml/xenstored/process.ml    | 12 ++++++------
 5 files changed, 18 insertions(+), 39 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 70c4348552..ace2aa5b4f 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,8 +277,6 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 3279b19b1b..72629ee38b 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -570,16 +570,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -589,8 +590,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:33:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:33:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434880.687630 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGB-0005O4-V3; Tue, 01 Nov 2022 15:33:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434880.687630; Tue, 01 Nov 2022 15:33:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGB-0005Nw-Rw; Tue, 01 Nov 2022 15:33:03 +0000
Received: by outflank-mailman (input) for mailman id 434880;
 Tue, 01 Nov 2022 15:33:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGA-0005Nm-PQ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGA-0001La-On
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGA-0003Rp-OB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=2ieu8NLXywUF/5A47wOuhJu55kHq2D3hAhWvv8KTby4=; b=RQ35n9pKC43ZIsUhpg1UhPsjhk
	TAZE3ran43dFCjSX+zbWCS26X3eZ78Q79zw1AnwUkrh6CXWBRbN9Ao++PJYM8jgWYUsN0LFwON199
	JbzOggQjEfG7MJORN6ew+lgsW1ERg7zbvVvdJ/RfuAfGX725wFYJikyiVpN48v54C43A=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1optGA-0003Rp-OB@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:33:02 +0000

commit b8b3734996f7ce0bfe2e28abed0eeab22d492a19
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 19171fb5d888b4467a7073e8febc5e05540956e9)
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:33:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:33:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434881.687634 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGM-0005Qi-0i; Tue, 01 Nov 2022 15:33:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434881.687634; Tue, 01 Nov 2022 15:33:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGL-0005Qb-Td; Tue, 01 Nov 2022 15:33:13 +0000
Received: by outflank-mailman (input) for mailman id 434881;
 Tue, 01 Nov 2022 15:33:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGK-0005QN-SX
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGK-0001Lf-Rt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGK-0003SF-RE
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ar3yphjlbMHZFgOcaHeFhOBsKoXfP80uXmFhWJjYtSk=; b=2Tx02VuxXlqrBo1DKA00kBKOO+
	eBd8gp1LWkI2gKleHxHkdWLjtkCzNhZtwiKWqpD+funpsln/yQx16c+Dxa9aVxyOt+5Am/oO2dutY
	tivDxgd1pJHu+Kjd/Dd/t8cbioi0CBQ8Bg0HYJ9F9yGNWgaIUou9t+gRs+I86nSUoToc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1optGK-0003SF-RE@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:33:12 +0000

commit 8db5e6f48e0794b16d0cec8ca79f3ba250835055
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96)
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index ace2aa5b4f..9aad451a2d 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -279,6 +407,7 @@ let get_transaction con tid =
 let do_input con = Xenbus.Xb.input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -286,7 +415,7 @@ let peek_output con = Xenbus.Xb.peek_output con.xb
 let do_output con = Xenbus.Xb.output con.xb
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 7efdf3e5e0..39190c19ec 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: (string, Connection.watch list) Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd _can_write =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -196,3 +215,13 @@ let debug cons =
 	let anonymous = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.anonymous [] in
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
+
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 1a5d2f34a6..9e52367094 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 72629ee38b..d2a3ba064e 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -56,7 +56,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -66,8 +66,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -99,6 +100,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -207,7 +222,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -366,7 +381,7 @@ let do_watch con t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -397,7 +412,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -565,7 +580,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -593,6 +609,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 0b6343dfc7..4f8fab2dd1 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -102,6 +102,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:33:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:33:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434882.687637 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGW-0005U2-4T; Tue, 01 Nov 2022 15:33:24 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434882.687637; Tue, 01 Nov 2022 15:33:24 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGW-0005Tu-1m; Tue, 01 Nov 2022 15:33:24 +0000
Received: by outflank-mailman (input) for mailman id 434882;
 Tue, 01 Nov 2022 15:33:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGU-0005Tj-VV
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGU-0001Lm-Uv
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGU-0003T4-UA
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=d9+QEGNGgAxLvWszy0aNYg5coFkwenaJfcqElGelNyY=; b=CrhBkKViNQGcx7IJHGo+4hEBmi
	OELaoNBpiPiVA3Y+V9ilVq6SKBwvGKeG2b2TBJWDwo1uSGGa7+qvX4Lm/XnOw89XULCp1u7LeDDvL
	g8x5UGOPMkJMojbZdxvLgztQDHZ5cmN9WijcPZ11kqpzzByAoowvQq5UuRWijXr8FR2E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1optGU-0003T4-UA@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:33:22 +0000

commit 2cf13721414dc5b380dc3c60e0f20c9cb416dbb3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c7bc20d8d123851a468402bbfc9e3330efff21ec)
---
 SUPPORT.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/SUPPORT.md b/SUPPORT.md
index c45390a245..dd9702bfe4 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -175,6 +175,17 @@ Support for running qemu-xen device model in a linux stubdomain.
 
     Status: Tech Preview
 
+## Xenstore
+
+### C xenstored daemon
+
+    Status: Supported
+
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+
 ## Toolstack/3rd party
 
 ### libvirt driver for xl
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:33:34 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:33:34 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434883.687642 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGg-0005Ww-6J; Tue, 01 Nov 2022 15:33:34 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434883.687642; Tue, 01 Nov 2022 15:33:34 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGg-0005Wp-3H; Tue, 01 Nov 2022 15:33:34 +0000
Received: by outflank-mailman (input) for mailman id 434883;
 Tue, 01 Nov 2022 15:33:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGf-0005WY-2Z
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGf-0001Ls-1p
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:33 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGf-0003Td-16
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:33 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=oY3gImXX3TvPF/+/ggWmhUnyRsDSoLuXgZ2U7WNNMJ4=; b=vHjY9sqqGgqYtofr91o0emLet0
	ARZ39+awcoVfUyMgHu5PddgwAlBNSEyohYEUb/nyYtirsYfFwuUsAQvJM6tMxaE/eR+3JHe+cf9Ad
	uSjL1NwRnMG2bGJ8cvk4zGqHcPrjWsLNRpHUuMLdQayWziXyjMDOaC4z34uQ1D7JgAjg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1optGf-0003Td-16@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:33:33 +0000

commit 55e23bf410bf20d27ef5555a73eab2a8a2602b39
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2a587de219cc0765330fbf9fac6827bfaf29e29b)
---
 tools/xenstore/xenstored_control.c     | 29 ++++++-------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 27 +++++++-----
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 116 insertions(+), 75 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 0227a55656..05e38e576a 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -30,11 +30,11 @@
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -46,7 +46,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -147,7 +147,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -159,7 +159,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -172,7 +172,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 }
 
 #ifdef __MINIOS__
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	if (num)
@@ -184,7 +184,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 #else
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -199,7 +199,7 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -239,7 +239,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -251,7 +251,7 @@ static int do_control_print(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -268,7 +268,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd, len = 0;
@@ -304,7 +304,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	int num;
 	int cmd;
@@ -316,7 +317,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (num < 1)
 		return EINVAL;
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) != num)
@@ -324,7 +325,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 
 	for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++)
 		if (streq(vec[0], cmds[cmd].cmd))
-			return cmds[cmd].func(in, conn, vec + 1, num - 1);
+			return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 
 	return EINVAL;
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index 207e0a6fa3..faa955968d 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,4 +16,5 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 6ed1ae2614..28724ef10a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1147,11 +1147,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1160,7 +1162,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1172,7 +1174,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1199,7 +1202,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1215,11 +1218,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1399,7 +1404,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1413,12 +1419,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1429,18 +1435,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1448,10 +1455,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 		/* No permissions? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1549,22 +1556,23 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1579,7 +1587,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1589,13 +1597,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1608,7 +1618,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1625,7 +1636,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1640,7 +1651,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1675,7 +1686,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1683,7 +1694,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1756,6 +1768,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	if ((unsigned int)type >= XS_TYPE_COUNT || !wire_funcs[type].func) {
 		eprintf("Client unknown operation %i", type);
@@ -1776,10 +1789,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 47e8010b34..417ff81181 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -333,7 +333,7 @@ bool domain_can_write(struct connection *conn)
 	return ((intf->rsp_prod - intf->rsp_cons) != XENSTORE_RING_SIZE);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -475,7 +475,8 @@ static void domain_conn_reset(struct domain *domain)
 }
 
 /* domid, gfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -551,7 +552,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -598,7 +600,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -613,7 +616,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -628,7 +632,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -636,18 +641,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -668,7 +672,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index e013a9991c..732eb8fa75 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -22,25 +22,32 @@
 void handle_event(void);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(void);
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6e29118c80..cd592845e7 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -487,7 +487,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -500,8 +501,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -548,7 +549,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -564,8 +566,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	list_del(&trans->list);
 	conn->transaction_started--;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 19d0fb01b1..13627ce972 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -184,7 +184,7 @@ static int destroy_watch(void *_watch)
 	return 0;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -200,7 +200,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 		/* check if valid event */
 	} else {
 		relative = !strstarts(vec[0], "/");
-		vec[0] = canonicalize(conn, in, vec[0]);
+		vec[0] = canonicalize(conn, ctx, vec[0]);
 		if (!vec[0])
 			return ENOMEM;
 		if (!is_valid_nodename(vec[0]))
@@ -250,7 +250,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -258,7 +259,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 03094374f3..40455dff5d 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:33:44 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:33:44 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434884.687648 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGq-0005ZK-9C; Tue, 01 Nov 2022 15:33:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434884.687648; Tue, 01 Nov 2022 15:33:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optGq-0005ZC-54; Tue, 01 Nov 2022 15:33:44 +0000
Received: by outflank-mailman (input) for mailman id 434884;
 Tue, 01 Nov 2022 15:33:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGp-0005Z4-5X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGp-0001MU-4s
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGp-0003UA-4B
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ifZ+x3M/Y9oYZi3RP8aHifpPPXGvHv8EvFF3ZZbbkuU=; b=aGp7TvrEHyM7FSOvKdoKWDmm1M
	qCBSS5mGP/ltYSen37XF0yNK7/mvuPSoY2h48043DQPN/AOAfTMje1kdRZDQiz9tcnSeg1l3TVZ2a
	ZmjggXcriIlxu0RRH9CTccukQQsJykWDDFSHoXDY4yinBpLab8/0mzmwHmG9zYTW44vY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: fix checking node permissions
Message-Id: <E1optGp-0003UA-4B@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:33:43 +0000

commit 2761f00a40665e97e1851880089fc888b378efc7
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ab128218225d3542596ca3a02aee80d55494bef8)
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 28724ef10a..34a8469dd6 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1642,6 +1642,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 417ff81181..8dcc1c20ab 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -859,7 +859,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -867,20 +866,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -893,8 +910,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -911,8 +926,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 732eb8fa75..bab405209e 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,6 +65,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:33:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:33:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434885.687651 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optH1-0005df-DX; Tue, 01 Nov 2022 15:33:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434885.687651; Tue, 01 Nov 2022 15:33:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optH1-0005dY-9D; Tue, 01 Nov 2022 15:33:55 +0000
Received: by outflank-mailman (input) for mailman id 434885;
 Tue, 01 Nov 2022 15:33:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGz-0005dL-8i
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGz-0001Mb-7r
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optGz-0003W8-7A
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:33:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=jqIMHD2CnmuhiG8lXimWz5muWn3zHCu0sYfzuHbFQAc=; b=D1RyO0efT6D0y+yp1yQIPG2l7f
	e2ryK5tS74r0jIhLhfAqtAV1+9SSdH75c9NLkwutkvFQ6nGOonAC/ieETGdq0LOlan44wZid6mXGT
	c1oNIxYDvUDMDt5DD0ACZTgrEXhEtsLB2/qh9KjhcsR/Ky8KrTvgFaBTEdBc9gEd78sI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1optGz-0003W8-7A@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:33:53 +0000

commit 4d2fe1d32c3bb6e966522840e2080377db9e9f65
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 110 ++++++++++++++++++++++++++--------------
 1 file changed, 72 insertions(+), 38 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 34a8469dd6..e7971c828e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1254,57 +1254,91 @@ static char *basename(const char *name)
 	return strrchr(name, '/') + 1;
 }
 
-static struct node *construct_node(struct connection *conn, const void *ctx,
-				   const char *name)
+static int add_child(const void *ctx, struct node *parent, const char *name)
 {
 	const char *base;
 	unsigned int baselen;
-	struct node *parent, *node;
-	char *children, *parentname = get_parent(ctx, name);
-
-	if (!parentname)
-		return NULL;
+	char *children;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
-
-	/* Add child to parent. */
 	base = basename(name);
 	baselen = strlen(base) + 1;
 	children = talloc_array(ctx, char, parent->childlen + baselen);
 	if (!children)
-		goto nomem;
+		return ENOMEM;
 	memcpy(children, parent->children, parent->childlen);
 	memcpy(children + parent->childlen, base, baselen);
 	parent->children = children;
 	parent->childlen += baselen;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
-
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
-
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
+	return 0;
+}
+
+static struct node *construct_node(struct connection *conn, const void *ctx,
+				   const char *name)
+{
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
+
+	if (!parentname)
+		return NULL;
+
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
+
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
+
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
+
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
+
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:34:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:34:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434886.687654 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHB-0005g9-EC; Tue, 01 Nov 2022 15:34:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434886.687654; Tue, 01 Nov 2022 15:34:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHB-0005g2-B4; Tue, 01 Nov 2022 15:34:05 +0000
Received: by outflank-mailman (input) for mailman id 434886;
 Tue, 01 Nov 2022 15:34:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optH9-0005fn-BU
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optH9-0001N0-Aj
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optH9-0003Wm-AA
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=q3YmXHlNVZqS9pNY7iM/PlyXMt3weJKZr0Fjptk7klU=; b=xJkWudumdZuwbrc3WIKni1lIfj
	QKJpAbIJnV6ILTyt8dRbRG84N08v1ZD2clyvbt987jUqeB6ehkZMgvrYv0Tf+CZI3FqlqAkTwHqx3
	M1kpgYpVzpMHpOKMvHGfBFaKyZu+Nufd5VG0CiFgJSEdpqETsFWM/uCt8Ue7nvS7qMu8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1optH9-0003Wm-AA@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:34:03 +0000

commit 7d4c2dea43b07249bfb6392e442afef4189b12a8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4)
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e7971c828e..cef9fc1c1e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1505,15 +1505,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1523,7 +1523,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2125,6 +2127,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2173,12 +2186,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2195,11 +2203,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:34:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:34:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434887.687658 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHL-0005jG-Fq; Tue, 01 Nov 2022 15:34:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434887.687658; Tue, 01 Nov 2022 15:34:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHL-0005j8-Ct; Tue, 01 Nov 2022 15:34:15 +0000
Received: by outflank-mailman (input) for mailman id 434887;
 Tue, 01 Nov 2022 15:34:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHJ-0005it-EM
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHJ-0001NA-Dj
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHJ-0003Xn-D1
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=bTP1MmmXmgN1EMo5eq8LBmMHz2OhSEy+F5dXp+wMQR0=; b=4TaCyA0+I9XVdZABXZN4eezvTa
	Tmv+c1qb8XT0PswC6qMU2cGjhHBM5oKsUxdRaVHMPpM2P3r5q4DzKDTFoZlT3Zl61Cowe16ThUm5g
	UJ9r3tUHii35P+/QxAATDRniYPdvt9AsQT5uPLAtJoOSJGlgzkQRAzDNUC8n5UGIQQ7U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: add generic treewalk function
Message-Id: <E1optHJ-0003Xn-D1@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:34:13 +0000

commit 4e1974248e895158e546e2294e87a0905217ce19
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d7c5d19bc27492360196e7dad2b227908564fff)
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index cef9fc1c1e..47559a85d4 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1733,6 +1733,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2105,18 +2234,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2172,7 +2289,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 5abf06c21c..fc9882ac37 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -167,6 +167,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -278,6 +279,45 @@ int do_tdb_delete(struct connection *conn, TDB_DATA *key,
 
 void conn_free_buffered_data(struct connection *conn);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:34:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:34:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434888.687662 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHV-0005mU-HD; Tue, 01 Nov 2022 15:34:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434888.687662; Tue, 01 Nov 2022 15:34:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHV-0005mM-EV; Tue, 01 Nov 2022 15:34:25 +0000
Received: by outflank-mailman (input) for mailman id 434888;
 Tue, 01 Nov 2022 15:34:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHT-0005ls-HL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:23 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHT-0001NF-Gi
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:23 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHT-0003Yu-G4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:23 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=CFqGGVUM2U72FkhU4GtXVl/Q+vtxfTlmLKOiTPvDzlk=; b=mEN4FfUrpd/DoJk+EISJ3bmhTl
	42lRc3LQ86ks2qUkqi+LbNm8tccSh68WV5MglpblnuPpU6oI24iy7EobNiDTh4bTGZFs6F8eilqua
	reaf4SIik6WMbPPlgC1fjEF6BgRPSTncHb3Nt3qW4LaKiY/zqSs5UCaOklhSjzEDGTkg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: simplify check_store()
Message-Id: <E1optHT-0003Yu-G4@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:34:23 +0000

commit 1de79dcf1bf08dd71ebfa083ff2365f06f69cd6e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 70f719f52a220bc5bc987e4dd28e14a7039a176b)
---
 tools/xenstore/xenstored_core.c | 43 ++++++++++++++---------------------------
 1 file changed, 15 insertions(+), 28 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 47559a85d4..302fb5b93c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2277,46 +2277,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2326,19 +2314,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:34:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:34:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434889.687667 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHf-0005po-Jr; Tue, 01 Nov 2022 15:34:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434889.687667; Tue, 01 Nov 2022 15:34:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHf-0005pg-G6; Tue, 01 Nov 2022 15:34:35 +0000
Received: by outflank-mailman (input) for mailman id 434889;
 Tue, 01 Nov 2022 15:34:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHd-0005pT-KF
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHd-0001NP-Jd
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:33 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHd-0003Zf-J0
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:33 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=/OTmpBp4Iz/OChfrYVvKwoDzxiY9P+gS2SwHSGFwwDA=; b=e21gLcfU59lhdj8zfRmNlrt3NS
	22+ckST77+aEck3GbV7NRTMr3TGLsrf2orsbYImt0jbwqBoZ/jGOs+oRv+FKfvLFI38OweNYrFgJu
	iDF1MTEZwEO/aTbUujH6mZoR76hp82K2QJ4HQ1xCtkMp+1GA7BTufXTRDEsZ6Jz9rWSw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: use treewalk for check_store()
Message-Id: <E1optHd-0003Zf-J0@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:34:33 +0000

commit 7f969f391e7714c20a50f1bee108e04c07f971f1
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 302fb5b93c..1cc11d0b1c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2244,18 +2244,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2269,70 +2257,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
-
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
+	struct hashtable *reachable = arg;
 
-			childnode = read_node(NULL, childname, childname);
-
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2381,24 +2328,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char * root = talloc_strdup(NULL, "/");
-	struct hashtable * reachable =
-		create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
+
+	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
 		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:34:44 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:34:44 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434890.687670 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHo-0005sZ-M9; Tue, 01 Nov 2022 15:34:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434890.687670; Tue, 01 Nov 2022 15:34:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHo-0005sR-JV; Tue, 01 Nov 2022 15:34:44 +0000
Received: by outflank-mailman (input) for mailman id 434890;
 Tue, 01 Nov 2022 15:34:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHn-0005sJ-NA
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHn-0001Nj-MS
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHn-0003aQ-Lq
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=DOQEpCMlv1Ln7PxD9mTPpMX1PHMPQD3r8PPc1NaAN98=; b=WlSYl0l2b6lTDdqgcfDNBVELNV
	oQNdEEbAolzkK9KCB6sg/cTgr01EUrWdvzl60CiijY1B8xZvia/pvlXF8b3tTSLX8UPNq9je1gCdo
	EFZBdU+fNzOTeBubVUEFeAdr06rj/XJE2Ed5KDnnnHyrAZ6gcd2hVgFNKEdQNDKuKL4g=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1optHn-0003aQ-Lq@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:34:43 +0000

commit baa5f58a69b32691bf0f1e98555ebe0bfd9e6314
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ea16962053a6849a6e7cada549ba7f8c586d85c6)
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 1cc11d0b1c..5bb7b85213 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1233,21 +1233,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1516,69 +1501,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1586,9 +1561,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1623,7 +1610,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:34:54 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:34:54 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434891.687674 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHy-0005vZ-O4; Tue, 01 Nov 2022 15:34:54 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434891.687674; Tue, 01 Nov 2022 15:34:54 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optHy-0005vP-L9; Tue, 01 Nov 2022 15:34:54 +0000
Received: by outflank-mailman (input) for mailman id 434891;
 Tue, 01 Nov 2022 15:34:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHx-0005vC-Q4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHx-0001Nn-PQ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optHx-0003bM-Ol
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:34:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=c5kHhGLwSsPt3RjmnbWSSVZrsj76/sn+NIacuyQNIm0=; b=goDZXHY+SjcX3yBU1P2mGL5AsM
	Z6KST1uoh208GeYZ4e5LBPt5vkglnwkxec9vak7TgccmICZOvP6qRC5oVo7xIUGd+60If/XHpl8Eo
	Iq0abI+BwIALn9ot78sj3qs+KEqSYXVM8FhwjGsXPaC+TeS74ZU1td1LOK9sjWScDSC0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1optHx-0003bM-Ol@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:34:53 +0000

commit e5bdcec53ad9c247d90d22cca6fb0b66e35cb81c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 755d3f9debf8879448211fffb018f556136f6a79)
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 85 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 81 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5bb7b85213..eb1d7c2b3b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -79,6 +79,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -664,7 +665,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -707,7 +708,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1548,7 +1549,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1610,7 +1611,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2446,6 +2447,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2469,6 +2472,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 	{ NULL, 0, NULL, 0 } };
@@ -2543,7 +2547,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2579,6 +2583,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index fc9882ac37..ec24c27ac2 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -204,6 +204,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(void);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 void check_store(void);
@@ -242,6 +245,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8dcc1c20ab..e798cd7475 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -200,10 +200,65 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		key.dptr = (char *)node->name;
+		key.dsize = strlen(node->name);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -835,15 +890,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -904,23 +959,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -938,15 +981,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1065,7 +1108,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index bab405209e..5bd253395d 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,7 +64,7 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:35:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:35:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434892.687678 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optI8-0005yk-QD; Tue, 01 Nov 2022 15:35:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434892.687678; Tue, 01 Nov 2022 15:35:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optI8-0005yd-Mx; Tue, 01 Nov 2022 15:35:04 +0000
Received: by outflank-mailman (input) for mailman id 434892;
 Tue, 01 Nov 2022 15:35:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optI7-0005yU-TB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optI7-0001OA-SU
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optI7-0003ce-Rk
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=snXalj8TNCGe4G1giQPH6EXwZtshR29ghIzpA2HvOv0=; b=s6wFRz1bf00GzBjQkLTYJ44DN8
	U1xgkL2Q8G+U4mr9njv+c2VWaRn72/Sa/SJAfn/VNiCF8Jke0mMyXyRlD6e6xvxBgik8lQPRA2sKy
	/i6AIvAYREDB/lpfuoXoSlJntKetU8vykXZnbd/VLjJWVQaZ+i7tnLxwE/KneeFATwTU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: make the internal memory data base the default
Message-Id: <E1optI7-0003ce-Rk@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:35:03 +0000

commit 39254879e3ec7e765097eb9f27b2773309735cab
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d174fefa90487ddd25ebc618028f67b2e8a1f795)
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 4ce8299c3c..2dfc78d4de 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -137,9 +137,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom = xc_dom_allocate(xch, cmdline, NULL);
     if ( !dom )
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index eb1d7c2b3b..7ed852fd79 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2134,7 +2134,7 @@ static void accept_connection(int sock, bool canwrite)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2446,7 +2446,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2471,7 +2472,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2547,7 +2548,8 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:Q:q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2581,7 +2583,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:35:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:35:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434894.687692 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optIJ-0006K3-3t; Tue, 01 Nov 2022 15:35:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434894.687692; Tue, 01 Nov 2022 15:35:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optIJ-0006Jt-1A; Tue, 01 Nov 2022 15:35:15 +0000
Received: by outflank-mailman (input) for mailman id 434894;
 Tue, 01 Nov 2022 15:35:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIH-0006JW-WB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIH-0001OF-VR
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIH-0003db-Ul
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=UT58wxx7v85tEqD9u7ojwcU98SSrEoK+32RYvlKqmWs=; b=ERSQ/AAmMUkzLUCkjv1WhEKl8S
	wNm2lZx3O5OR3w3rYHM99VmgohmMFRBHFizQhzxUkOm8UDhXAlmSis0ZHvbT1wXSnAHjCCfroRFgL
	lQ2bXWrJszT55WuDj9TynWXkEyTRaAtPK7SOhYXaNo+C+hWlBkSaLbuUhL2sTIg11WlM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] docs: enhance xenstore.txt with permissions description
Message-Id: <E1optIH-0003db-Ul@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:35:13 +0000

commit 7036cb93e334e006fe3b9685256fd75e4967e3fc
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d084d2c6dff7044956ebdf83a259ad6081a1d921)
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 1f42a377c1..6aa07c5ed8 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:35:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:35:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434896.687697 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optIT-0006UT-6w; Tue, 01 Nov 2022 15:35:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434896.687697; Tue, 01 Nov 2022 15:35:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optIT-0006UK-4F; Tue, 01 Nov 2022 15:35:25 +0000
Received: by outflank-mailman (input) for mailman id 434896;
 Tue, 01 Nov 2022 15:35:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIS-0006Sf-2m
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIS-0001OJ-24
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIS-0003ec-1N
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8023q8SwgtOq5b0CpS79cwf0FruOJUY21fM4FrGWuQg=; b=dbeky2/kvKNQyvq+FzoEf75og6
	5HDG0TI8dQaLlZzrRvP0MO2VW2EfbcoaETJ9TXSE9njD8BP3XjVX8NDQdWboawoQlQXZ17vf8leH4
	cUOBD1BtadvfxutjuNJwqAM4x/QkC14bpnbtNMIipIEXMRgeEEnTzzcVex/x5SGCnBNo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1optIS-0003ec-1N@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:35:24 +0000

commit 0cd209a7e302f0754b19d38143932c3c10d4d7cc
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit db471408edd46af403b8bd44d180a928ad7fbb80)
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 328d3a5198..d82764f60f 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -89,10 +89,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; List.iter (recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = List.rev_map walk node.children |> List.rev }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			List.rev_map walk node.children |> List.filter is_valid |> List.rev } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -446,11 +457,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:35:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:35:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434898.687700 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optId-0006c8-8O; Tue, 01 Nov 2022 15:35:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434898.687700; Tue, 01 Nov 2022 15:35:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optId-0006c2-5g; Tue, 01 Nov 2022 15:35:35 +0000
Received: by outflank-mailman (input) for mailman id 434898;
 Tue, 01 Nov 2022 15:35:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIc-0006aZ-5e
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIc-0001ON-4u
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIc-0003fU-4G
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sJdzbrC7nJA2ZsSY5Wk79Qh8LH6yp22oVqCIY79eTsw=; b=JeL0BJ0yoXs330F72kp1fEGrcn
	HZ5t8tg5RNfNfPrGW6qKaSHUnHBnPuVXnXOh3Mto9xln1Zy6/DALwkP02YVXNN4GrQewh7y/XSQI7
	IZJ+ygUpS1l9ZuC5Lv1UwmjtwSavWFRPp9p0rlIoSBdCB+0SWOTroJIcFfEz7kpPt1sw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1optIc-0003fU-4G@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:35:34 +0000

commit ecbfb3bd49526adf48f739445502aaff8e69e442
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3)
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index d2a3ba064e..027252ece8 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -587,7 +587,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:35:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:35:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434899.687705 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optIn-0006gf-9m; Tue, 01 Nov 2022 15:35:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434899.687705; Tue, 01 Nov 2022 15:35:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optIn-0006gW-7D; Tue, 01 Nov 2022 15:35:45 +0000
Received: by outflank-mailman (input) for mailman id 434899;
 Tue, 01 Nov 2022 15:35:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIm-0006fI-8F
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIm-0001Ou-7d
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIm-0003gH-70
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=FrdoDLY6TWCimJCSSnId2fr9bidYvU128suCDYUwUl8=; b=opl7JXJwVW+ySp40q3jI+ZUEjB
	JunQ/J2sOMfaP0JkbFX+Paz03N/SkR1TvJ/9AQZL+92Fgde5TZb7PI5B9ykj94M7liCPVskMB22Qm
	pUs/FQ6g8Q/nVgytqC7sV70La4TVlhgKfrIQZFhWJDNHgeruPK1qazcyQwUste6Vsq3c=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: fix deleting node in transaction
Message-Id: <E1optIm-0003gH-70@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:35:44 +0000

commit fd44be9ccb0b8704497498e45e020738a11d27e3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187)
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd592845e7..6297149986 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -424,7 +424,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:35:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:35:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434901.687709 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optIx-0006kc-Bd; Tue, 01 Nov 2022 15:35:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434901.687709; Tue, 01 Nov 2022 15:35:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optIx-0006kU-8n; Tue, 01 Nov 2022 15:35:55 +0000
Received: by outflank-mailman (input) for mailman id 434901;
 Tue, 01 Nov 2022 15:35:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIw-0006kG-BR
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIw-0001P5-Aj
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optIw-0003hN-A4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:35:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=rl8XtwB56/C+gQaVCD+k+E+DM/4ljx8PbAiBoSHhyaE=; b=YA4ZePjJKin5fx4MY/1lW0NBu9
	vSrMs89g5xpk0amPMFeYrcLxTja877+LhBW4kR7ffVSHKb2yWOwA7yZV8Z32nTyVHCM3BTx+qov4h
	wmRns6mlub14AkC2PdeSyAMhWSLG1Mj/oc5AUflmH1BAyph5f0ANGJLmrXH+WKcQGVXk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1optIw-0003hN-A4@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:35:54 +0000

commit 1c354767d58cd80224f0dfb107584bc8bd629b00
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff)
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 7ed852fd79..64ff80f5c5 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -634,8 +634,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -748,10 +747,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6297149986..5e4780e874 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -205,25 +206,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -246,7 +242,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -265,10 +260,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -279,9 +270,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -308,7 +300,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -327,7 +319,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -339,7 +331,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -377,100 +368,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -560,6 +541,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -581,13 +563,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -661,7 +647,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -673,11 +659,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:36:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:36:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434903.687713 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJ8-0006o8-DN; Tue, 01 Nov 2022 15:36:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434903.687713; Tue, 01 Nov 2022 15:36:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJ8-0006o1-AP; Tue, 01 Nov 2022 15:36:06 +0000
Received: by outflank-mailman (input) for mailman id 434903;
 Tue, 01 Nov 2022 15:36:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJ7-0006ns-5H
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJ7-0001PT-4X
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJ7-0003nf-40
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NT5YwUV6GxaWGYGDi+KvkYxMJPdzmhO79Qckd0rD//s=; b=RDjGiaSBMryB/lD5Z6P88dRc7l
	S+BHSROq1ksLfX8ces2in0GCI70lcUnpt26v9pQoX9ygeDTRr/cE8SgfKSIFnE0Lk/RYQ2rfM/GiP
	VCBrMZnjuVWe4RPhVG2K76Iw4ggPkZKxB7DlAf09onburjzkVO9jjDTGop081fGJ5PL0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1optJ7-0003nf-40@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:36:05 +0000

commit 149ebf0e0228ece2ec704f6ac2ec35f68e94a23f
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 1cd3cc7ea27cda7640a8d895e09617b61c265697)
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 08190ecc55..c952608468 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -975,9 +975,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -988,7 +987,7 @@ static int destroy_node(void *_node)
 
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -997,7 +996,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1019,23 +1019,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:36:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:36:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434904.687717 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJI-0006s4-H1; Tue, 01 Nov 2022 15:36:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434904.687717; Tue, 01 Nov 2022 15:36:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJI-0006rw-E9; Tue, 01 Nov 2022 15:36:16 +0000
Received: by outflank-mailman (input) for mailman id 434904;
 Tue, 01 Nov 2022 15:36:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJH-0006rk-85
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJH-0001Pq-7P
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJH-0003p7-6q
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=XzLpYY427FhDeIj+QcX/ZIMZqGO5u6Ilw/wF/kTQS7M=; b=E2+HIka98WzRssd4uEcTo3wtW4
	q3oLomz1vPd34XMkRQBRiSX/siCL81ac1r8T9hiOkor63aZ4qvZ9ag8Hp6qceFyHim5TKEEwqn4sE
	1SO8o20UEa+wEdTSVp92y5XhEORd04zeY5wERdFGtYYeYnnA6xCtbD77gNASQHqNSack=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1optJH-0003p7-6q@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:36:15 +0000

commit fcba6c74e1493a329563208ed1f3014dab54bd47
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34)
---
 tools/xenstore/xenstored_core.c        | 25 +++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c952608468..e0d6d23f3b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -466,15 +466,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
@@ -977,18 +979,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	key.dptr = (void *)node->name;
-	key.dsize = strlen(node->name);
-
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 196a6fd2b0..9369c4cbfd 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -119,6 +119,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 2881f3b2e4..4ffa183111 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -582,6 +582,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:36:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:36:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434905.687721 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJS-0006vB-IO; Tue, 01 Nov 2022 15:36:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434905.687721; Tue, 01 Nov 2022 15:36:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJS-0006v1-Fe; Tue, 01 Nov 2022 15:36:26 +0000
Received: by outflank-mailman (input) for mailman id 434905;
 Tue, 01 Nov 2022 15:36:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJR-0006un-B9
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJR-0001Pu-AR
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJR-0003px-9j
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=uTTqE4c8uQUm7t4Q9TW181Tvh9LL+I4WwiEfH3s3Ta8=; b=uPpUUtxWOLcDlXiJSpdVCk/3/c
	WObmV/rZBzHTzaQEt6X9i1f8enNJ/CuRmwuCpUYGfawVMLccoT9Wzpum8NOGOVwEx3bky78O9prQT
	PHoCtkUeeumQ3NgycHElRUvAZ0G4ZXb8YudUz8Ynzvh3ucYkMKnKBI5yfLbO9aNBUeNo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: split up send_reply()
Message-Id: <E1optJR-0003px-9j@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:36:25 +0000

commit 95fe444988f05f5b0d4fa5095a84842f83d87793
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32)
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 42 +++++++----------------
 3 files changed, 58 insertions(+), 59 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e0d6d23f3b..97ff35cd2b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -672,49 +672,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -722,8 +705,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 9369c4cbfd..2b0f796d9b 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -150,6 +150,7 @@ unsigned int get_strings(struct buffered_data *data,
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 9ff20690c0..6d8097376e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -72,37 +72,17 @@ static bool is_child(const char *child, const char *parent)
 	return child[len] == '/' || child[len] == '\0';
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
+static const char *get_watch_path(const struct watch *watch, const char *name)
 {
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
+	const char *path = name;
 
 	if (watch->relative_path) {
-		name += strlen(watch->relative_path);
-		if (*name == '/') /* Could be "" */
-			name++;
+		path += strlen(watch->relative_path);
+		if (*path == '/') /* Could be "" */
+			path++;
 	}
 
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
+	return path;
 }
 
 /*
@@ -181,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -252,7 +236,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:36:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:36:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434906.687726 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJc-0006yA-KX; Tue, 01 Nov 2022 15:36:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434906.687726; Tue, 01 Nov 2022 15:36:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJc-0006y2-HE; Tue, 01 Nov 2022 15:36:36 +0000
Received: by outflank-mailman (input) for mailman id 434906;
 Tue, 01 Nov 2022 15:36:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJb-0006xr-E1
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJb-0001QP-DF
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJb-0003qy-Ch
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0XY1v2Qhm2AJozs5+0HfAOk6ACASOmDBsBNrr8YdBaE=; b=1l00ezLEDuZUQIiJHISPOiEtZ6
	jBMy3pJzemgrhUNdhHKVsAwOS6CxJanE1HBaehCNzRzceBFcYC5CyEQ6J1qOgnpErtGhCjZsriifT
	C/HeNnI4yPJAWywciRKfHXdyqVRvBDNagUUsgHFVoBOstZLSJ5/ph2VsAo/fI4F2zzrc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1optJb-0003qy-Ch@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:36:35 +0000

commit 6f311278e9f8082378e236ab246ae160d76db008
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ead062a68a9c201a95488e84750a70a107f7b317)
---
 tools/xenstore/xenstored_core.c   | 26 +++++++++++++++++---------
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c |  7 +------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 97ff35cd2b..11b8d98634 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -205,6 +205,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -248,8 +263,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
@@ -1389,18 +1403,12 @@ static struct {
  */
 static void ignore_connection(struct connection *conn)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored\n", conn);
 
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2b0f796d9b..83d49693fc 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -226,6 +226,8 @@ extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
 
+void conn_free_buffered_data(struct connection *conn);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index cbd8e6b747..416b92cad4 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -406,15 +406,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:36:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:36:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434909.687729 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJm-00071Y-Lm; Tue, 01 Nov 2022 15:36:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434909.687729; Tue, 01 Nov 2022 15:36:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJm-00071Q-In; Tue, 01 Nov 2022 15:36:46 +0000
Received: by outflank-mailman (input) for mailman id 434909;
 Tue, 01 Nov 2022 15:36:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJl-00071F-H2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJl-0001S6-GM
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJl-0003rj-Ff
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=OUHo3bQ65E9af5Ah2D+4MLf1vJ8+V2PD913wb2oKQA0=; b=MXtrCc2mM7rO9Gzw/ROE0oaDme
	LWv0y7FetNHHr/QUoFMv9gfu5TGFyHSox5qfQlgrZZ5vTd8ssCzsSek4fzYHEHhSGUVeOzDAps4SB
	BFc6TWDYGA3F9xjd0t7tW3cJ00rAAbT4vgIA+ep6Ev/R6736eqZpIAsKtodKzpWIeqkQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: reduce number of watch events
Message-Id: <E1optJl-0003rj-Ff@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:36:45 +0000

commit 1761828e6d00110562bf869ae284c17f5496fc89
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297)
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 11b8d98634..8f8d10cee9 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1180,7 +1180,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1192,7 +1192,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1204,7 +1204,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1230,13 +1235,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 4ffa183111..6fbdb29dcd 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -329,6 +333,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -383,15 +410,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 6d8097376e..2f9367767e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:36:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:36:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434910.687733 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJw-00075S-Pg; Tue, 01 Nov 2022 15:36:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434910.687733; Tue, 01 Nov 2022 15:36:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optJw-00075L-N9; Tue, 01 Nov 2022 15:36:56 +0000
Received: by outflank-mailman (input) for mailman id 434910;
 Tue, 01 Nov 2022 15:36:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJv-00075C-Jz
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJv-0001SG-JO
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optJv-0003sc-Ig
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:36:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=HFxsotXhvqNmBzdBc1VnyIRW8Ty45yr6vUueWMVXOz4=; b=i22jQKvaexUXo+3ODZlpZ/8CnO
	hfHeyAJBltNsEI2VRaocR3ua3lCyoNEq7lfoW2laF/pT+wBMFNAXuBiklbEGdT4uqjILQ2c/Fxx+1
	4FIymRji329ivECRYMeixEKL7l5wMeuJ2ncLpoW+J/Yy2feIBkmhDPvnyhet32ujNJXE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: let unread watch events time out
Message-Id: <E1optJv-0003sc-Ig@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:36:55 +0000

commit cde36e0c369d0156e5f441635a2c45c0e28d926f
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 5285dcb1a5c01695c11e6397c95d906b5e765c98)
---
 tools/xenstore/xenstored_core.c | 127 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8f8d10cee9..5fb4714b35 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -103,6 +103,8 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -205,19 +207,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -331,6 +406,7 @@ static void initialize_fds(int sock, int *p_sock_pollfd_idx,
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -352,10 +428,12 @@ static void initialize_fds(int sock, int *p_sock_pollfd_idx,
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (domain_can_read(conn) ||
 			    (domain_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -699,6 +777,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -750,6 +829,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -2009,6 +2094,9 @@ static void usage(void)
 "  -W, --watch-nb <nb>     limit the number of watches per domain,\n"
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2030,6 +2118,7 @@ static struct option options[] = {
 	{ "trace-file", 1, NULL, 'T' },
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2041,6 +2130,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt, *sock = NULL, *ro_sock = NULL;
@@ -2052,7 +2174,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2097,6 +2219,9 @@ int main(int argc, char *argv[])
 		case 'A':
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 83d49693fc..3112c11811 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <dirent.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -56,6 +57,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -88,6 +91,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -199,6 +203,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:37:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:37:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434911.687737 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optK7-0007AA-Ra; Tue, 01 Nov 2022 15:37:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434911.687737; Tue, 01 Nov 2022 15:37:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optK7-0007A2-Ol; Tue, 01 Nov 2022 15:37:07 +0000
Received: by outflank-mailman (input) for mailman id 434911;
 Tue, 01 Nov 2022 15:37:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optK5-00079p-Nh
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optK5-0001Se-Mu
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optK5-0003tf-MA
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=4F4pJq+QoI1xZDtnP8S2M3xzIXoF8VKn1lIgmhO5sXk=; b=vRwisW03kSPAglcNE2WVyRfvbE
	lIkcvmDxl1B2b4ulE2sOKU/03ojic4XR0Mp1II13pkdrmdnKWPkR/njaf/Y1mtl6uRacQAaIg5dhs
	Vj/CbFIkAj2i2WkUZVASwHGbNHTAbyNl5wtAhWs9ratY+TA57gvW26Ywz2+yxwEAvq7k=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: limit outstanding requests
Message-Id: <E1optK5-0003tf-MA@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:37:05 +0000

commit 538b61b90393f21ba9ce8cc73fc9eb8fc046ade6
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 36de433a273f55d614c83b89c9a8972287a1e475)
---
 tools/xenstore/xenstored_core.c   | 78 ++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h   | 20 +++++++++-
 tools/xenstore/xenstored_domain.c | 37 ++++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 ++++++--
 5 files changed, 141 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5fb4714b35..5f1733112a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -102,6 +102,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -217,12 +218,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -238,6 +251,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -346,6 +383,7 @@ static bool write_messages(struct connection *conn)
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -359,6 +397,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -798,6 +841,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -805,7 +850,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -835,8 +881,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1572,6 +1623,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1642,6 +1694,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
 	new->is_ignored = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 
@@ -2094,6 +2147,9 @@ static void usage(void)
 "  -W, --watch-nb <nb>     limit the number of watches per domain,\n"
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2118,6 +2174,7 @@ static struct option options[] = {
 	{ "trace-file", 1, NULL, 'T' },
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2163,6 +2220,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt, *sock = NULL, *ro_sock = NULL;
@@ -2174,7 +2245,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2219,6 +2290,9 @@ int main(int argc, char *argv[])
 		case 'A':
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 3112c11811..edeaa96dd1 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -45,6 +45,8 @@ typedef int32_t wrl_creditt;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -52,6 +54,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -93,6 +106,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -154,7 +170,8 @@ unsigned int get_strings(struct buffered_data *data,
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -202,6 +219,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 416b92cad4..58b7e0fe2f 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -86,6 +86,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -288,8 +291,12 @@ bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	if (conn->is_ignored)
 		return false;
@@ -338,7 +345,7 @@ static struct domain *alloc_domain(void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -387,8 +394,6 @@ static int new_domain(struct domain *domain, int port)
 	domain->conn->id = domain->domid;
 
 	domain->remote_port = port;
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
 
 	return 0;
 }
@@ -929,6 +934,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5e00087206..4bff2e655b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -67,6 +67,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 2f9367767e..c50c0575f0 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -238,8 +241,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	talloc_set_destructor(watch, destroy_watch);
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:37:19 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:37:19 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434912.687740 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKH-0007Cv-Tm; Tue, 01 Nov 2022 15:37:17 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434912.687740; Tue, 01 Nov 2022 15:37:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKH-0007Cn-QO; Tue, 01 Nov 2022 15:37:17 +0000
Received: by outflank-mailman (input) for mailman id 434912;
 Tue, 01 Nov 2022 15:37:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKF-0007CX-RR
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKF-0001So-Px
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKF-0003uC-PM
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=a+IOvMmod9BJI6sKz05NwTCbVdx5NIabCpTSxumXToQ=; b=gYAU7cIgq537DrPnEqLnTdimju
	q/JOnIDXLps+Whaso1zmJZP9ppdushXISsy7rL10c2o3vVXiVvaxlSxTAhMxppG207GadpbD/OpjI
	nkgB6lQO9Ht4JSxOo4FEt4ojnAgbmgDI2q/nxfpqZEtMIyz+3IoxQfvpg+XbANYbr8qQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1optKF-0003uC-PM@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:37:15 +0000

commit 2963ee5d065ecd2fb8c7a5dcd9f1cff66f6497f2
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2)
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5f1733112a..0621023bca 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -821,6 +821,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -853,7 +854,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -875,12 +876,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index edeaa96dd1..1eb6131fc8 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -51,6 +51,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:37:27 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:37:27 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434918.687767 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKR-0007sF-OO; Tue, 01 Nov 2022 15:37:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434918.687767; Tue, 01 Nov 2022 15:37:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKR-0007s5-LT; Tue, 01 Nov 2022 15:37:27 +0000
Received: by outflank-mailman (input) for mailman id 434918;
 Tue, 01 Nov 2022 15:37:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKP-0007qC-TS
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKP-0001T1-St
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKP-0003up-SH
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=T3MRtkV87Xvfa1tw4DTC0QxTb2Y8PeLAxQkTfysRo5M=; b=roUuXgMUjTWJvsWronSx2Vj8z+
	dpxFm6M49WaGjHL997w3q/fXnj2M78o2hgYWWwJ/h9gJySQE5XlygEDhH8U1qfk3npSuCL5uYX6+x
	xVKMxu8p8gDHmbqyTdA77cjpELaY4Rm22zaAnyZqV4Y32HLdt7sStk8lyHNd2ipFX/Pk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: fix connection->id usage
Message-Id: <E1optKP-0003up-SH@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:37:25 +0000

commit e84ef3b0810c3fdf4db7728c69fca2dee77084a2
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831)
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index e4b8aa95ab..d3272e2ef9 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -180,7 +180,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	int cmd;
 	char **vec;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	num = xs_count_strings(in->buffer, in->used);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1eb6131fc8..98db4afcaa 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -93,7 +93,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this a read-only connection? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6fbdb29dcd..9bef6e72a5 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -483,7 +483,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:37:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:37:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434919.687772 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKb-00088T-Qd; Tue, 01 Nov 2022 15:37:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434919.687772; Tue, 01 Nov 2022 15:37:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKb-00088J-Mz; Tue, 01 Nov 2022 15:37:37 +0000
Received: by outflank-mailman (input) for mailman id 434919;
 Tue, 01 Nov 2022 15:37:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKa-00083s-0P
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKZ-0001Te-W2
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKZ-0003vy-VS
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=wTTJw5In+kPkCXeSqYQKJPJ0X0XgbejwrtIpxVEPU7A=; b=P9Z2bGpHv4SVMXwljSObNPjzcx
	xDI9TXy6tkJf8cJ9iGTf1a07jxUJVSBcRQyto/nsJ8ZN9clB+TjDUubD/abBqIqe7P5HsJNzD163u
	FrfXRHFYVnshRN/2LiB/uGnMAZOILEZHx61I+Nk76RBOQIR+i8weNipwFeqV3NtiJv4s=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1optKZ-0003vy-VS@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:37:35 +0000

commit 5fa4f2c6c8dbc225824a6f9c407b11c510d98674
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit dbef1f7482894c572d90cd73d99ed689c891e863)
---
 tools/xenstore/xenstored_control.c     |   1 +
 tools/xenstore/xenstored_core.c        |  39 +++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 5 files changed, 107 insertions(+), 50 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index d3272e2ef9..715e0d2a9e 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -25,6 +25,7 @@
 #include "talloc.h"
 #include "xenstored_core.h"
 #include "xenstored_control.h"
+#include "xenstored_domain.h"
 
 struct cmd_s {
 	char *cmd;
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 0621023bca..98d242e062 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -543,7 +543,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -565,7 +565,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1159,13 +1159,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1215,8 +1219,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1497,10 +1505,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
 
-	if (write_node(conn, node, false))
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
+
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 58b7e0fe2f..f4134db3e7 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -362,6 +363,18 @@ static struct domain *alloc_domain(void *context, unsigned int domid)
 	return domain;
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port)
 {
 	int rc;
@@ -774,30 +787,28 @@ void domain_init(void)
 	virq_port = rc;
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -833,7 +844,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -843,8 +854,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -863,25 +880,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -891,13 +908,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4bff2e655b..4edf1dba94 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -57,10 +57,10 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 9bef6e72a5..bf2fda8234 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -523,8 +523,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:37:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:37:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434923.687775 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKl-0008OM-RL; Tue, 01 Nov 2022 15:37:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434923.687775; Tue, 01 Nov 2022 15:37:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKl-0008OE-OY; Tue, 01 Nov 2022 15:37:47 +0000
Received: by outflank-mailman (input) for mailman id 434923;
 Tue, 01 Nov 2022 15:37:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKk-0008Ks-3k
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKk-0001To-37
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKk-0003wY-2L
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=lc/BOsPM8HxHLk/uZb//RPPPNCt/i84qBY0wFRHBJQk=; b=wpwlI4VPk5LTEIrhCe/iKJfThl
	EWdV5yN/PKgyDmb/VS9HitcmqiKNzXc0jVnfphPHzlkIRTn9OEBmBkjCrVmqmBFJjXUUljCsg0YDt
	e+lwRyJUtUalW08RlhMPPovP0gQtiCCHRoAJbpq+AUeguVZVX1gbJyr/qar16TzcOnyI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1optKk-0003wY-2L@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:37:46 +0000

commit f859218309f09ec6d425e02b583e4494924304ad
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 268369d8e322d227a74a899009c5748d7b0ea142)
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index cc7dfc8c64..34db3b7847 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -59,4 +59,8 @@
     })
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 98d242e062..57c9991292 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -102,6 +102,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
@@ -500,6 +501,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -521,14 +523,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -543,19 +544,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -670,7 +688,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -733,7 +751,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1115,7 +1133,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1394,7 +1412,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1422,7 +1440,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2192,6 +2210,8 @@ static void usage(void)
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2273,6 +2293,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 98db4afcaa..7e371253d2 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -34,6 +34,7 @@
 #include "list.h"
 #include "tdb.h"
 #include "hashtable.h"
+#include "utils.h"
 
 /* DEFAULT_BUFFER_SIZE should be large enough for each errno string. */
 #define DEFAULT_BUFFER_SIZE 16
@@ -223,6 +224,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index bf2fda8234..778b7e439c 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -266,6 +269,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -303,6 +311,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:37:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:37:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434927.687779 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKv-0008WS-TO; Tue, 01 Nov 2022 15:37:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434927.687779; Tue, 01 Nov 2022 15:37:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optKv-0008WK-QA; Tue, 01 Nov 2022 15:37:57 +0000
Received: by outflank-mailman (input) for mailman id 434927;
 Tue, 01 Nov 2022 15:37:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKu-0008Vw-6n
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKu-0001U0-69
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optKu-0003x6-5Y
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:37:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=y/jVqJYGaK5w+wrq7C50yjmIDVXdpdKX1I40kmqv39Q=; b=09k+6Vew+Y0C0pwB7iexfRWung
	SnUZOl3PYKaMSOCG3M3p6VqWc9rAxo+5RxolBYU9D/95vYqYVBj+96uqiXuGyes+fDUETmaul0/rh
	MVC85ljxW+rMu7jJi4TC55xjCSyZPO8LVXHHVOu5t69h9dLra1I4IIWlpU5KhBsrz1Qo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1optKu-0003x6-5Y@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:37:56 +0000

commit 8cd25aecce59e420b25a75b5643a8d668ee22c4c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 60e2f6020dea7f616857b8fc1141b1c085d88761)
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 2 ++
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 57c9991292..1335051a53 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1832,7 +1832,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -1871,7 +1872,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(void)
+void setup_structure(void)
 {
 	char *tdbname;
 	tdbname = talloc_strdup(talloc_autofree_context(), xs_daemon_tdb());
@@ -1889,6 +1890,7 @@ static void setup_structure(void)
 	manual_node("/", "tool");
 	manual_node("/tool", "xenstored");
 	manual_node("/tool/xenstored", NULL);
+	domain_entry_fix(dom0_domid, 3, true);
 
 	check_store();
 }
@@ -2402,9 +2404,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure();
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init)
 		domain_init();
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 7e371253d2..d95e4262a9 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -195,6 +195,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(void);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 void check_store(void);
 void corrupt(struct connection *conn, const char *fmt, ...);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index f4134db3e7..8bf9db2d96 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -739,6 +739,8 @@ static int dom0_init(void)
 	if (dom0->interface == NULL)
 		return -1;
 
+	setup_structure();
+
 	talloc_steal(dom0->conn, dom0); 
 
 	xenevtchn_notify(xce_handle, dom0->port);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:38:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:38:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434929.687785 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optL6-0000As-1o; Tue, 01 Nov 2022 15:38:08 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434929.687785; Tue, 01 Nov 2022 15:38:08 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optL5-0000Ae-To; Tue, 01 Nov 2022 15:38:07 +0000
Received: by outflank-mailman (input) for mailman id 434929;
 Tue, 01 Nov 2022 15:38:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optL4-0000AE-A3
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:06 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optL4-0001UK-9N
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:06 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optL4-0003y4-8e
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=fekieQ51ee8VFs32As66lZf+pBO4wuaQAjlpjT6ft0Y=; b=3R2dNYhhc/XnaMwuaAyHeZickr
	u/QCiiUUO5xhZuzUJRP0B04vX6br1RqOCnLZYB31kf55vRXMaA41Qfri/x8fq1SYtb/SpYY95Wdin
	8AQ6ktJoSqKU7v+fk4Y8roif96Sp0Cb2AGls5yFLd0eyLJ6qXgSK1SRXhP9+W0Zsn+Ow=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1optL4-0003y4-8e@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:38:06 +0000

commit b917d57d46c3769f6b482d70c6a54a5dbdd7d87a
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d4a8ec7a93faedbe54fd197db146de628459e77)
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 1335051a53..217096d91a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -104,6 +104,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2214,7 +2216,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2240,6 +2249,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2285,7 +2295,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2293,11 +2303,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2312,7 +2327,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2358,7 +2373,10 @@ int main(int argc, char *argv[])
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index d95e4262a9..4e53072e63 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -226,6 +226,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8bf9db2d96..2b23452e0c 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -84,6 +84,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -297,6 +304,9 @@ bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	if (conn->is_ignored)
@@ -941,6 +951,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4edf1dba94..3a8c6bab48 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,6 +64,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:38:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:38:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434930.687787 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLG-0000FB-2F; Tue, 01 Nov 2022 15:38:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434930.687787; Tue, 01 Nov 2022 15:38:18 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLF-0000F1-VY; Tue, 01 Nov 2022 15:38:17 +0000
Received: by outflank-mailman (input) for mailman id 434930;
 Tue, 01 Nov 2022 15:38:16 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLE-0000Ee-DB
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:16 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLE-0001UO-Ca
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:16 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLE-0003yn-Bt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:16 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=RyrMkS0uo/ALeqSShO4XuNMZAMQfCKgwOpJxqyGnQ2E=; b=COf2OlbBZ3HEo2g1M6CzsYwnBV
	XVT6pzQS5gqndkk4CPBF0aD+juRqL40sGCHat/GOimtv1cRebq5/+3jKzayXyT+Id3Ra3q+mWonLo
	8HKyJLDO+4FEeLIUN5TeQvuQovx+Z5AotojTlel3urKHuqB4ewcobeY+Nm29wt20RhCA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: add memory accounting for responses
Message-Id: <E1optLE-0003yn-Bt@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:38:16 +0000

commit 115156c416ad9a12d72d14f2df0c982ea1a254c4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    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 f6d00133643a524d2138c9e3f192bbde719050ba)
---
 tools/xenstore/xenstored_core.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 217096d91a..4f29439ad8 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -254,6 +254,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -843,11 +845,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -912,6 +917,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:38:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:38:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434932.687791 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLQ-0000Ix-3s; Tue, 01 Nov 2022 15:38:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434932.687791; Tue, 01 Nov 2022 15:38:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLQ-0000Ik-0u; Tue, 01 Nov 2022 15:38:28 +0000
Received: by outflank-mailman (input) for mailman id 434932;
 Tue, 01 Nov 2022 15:38:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLO-0000IX-GE
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLO-0001Uq-Fd
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:26 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLO-0003zi-F3
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:26 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=80tQGPEwinZf6hZbI5Q+qjibHQKBDTl4KOWXa7Ozudg=; b=UeXCZMRPWy83bcCGUOHsxdF2Uh
	Dif2RVbHst93brIHVbTltvBCkXD1o90WbzBhZ1Lv4yIitVDrMhxmzf+VG8hEW2TtHm6bn2cHUsjC1
	BO6ZFoJcnwnFhIJEaKcUI1+atZNP7XTUUzaZ+evWDsD0pali9U7s17FQHJtWMSFE1dvM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: add memory accounting for watches
Message-Id: <E1optLO-0003zi-F3@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:38:26 +0000

commit c17d49134aef23c8d017a64e5e36c626779bf863
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    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 7f9978a2cc37aaffab2fb09593bc598c0712a69b)
---
 tools/xenstore/xenstored_core.c  | 1 +
 tools/xenstore/xenstored_watch.c | 7 ++++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 4f29439ad8..eca04e734a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -404,6 +404,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index c50c0575f0..7118c30e8c 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -224,7 +224,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 		return ENOMEM;
 	watch->node = talloc_strdup(watch, vec[0]);
 	watch->token = talloc_strdup(watch, vec[1]);
-	if (!watch->node || !watch->token) {
+	if (!watch->node || !watch->token ||
+	    domain_memory_add_chk(conn->id, strlen(vec[0]) + strlen(vec[1]))) {
 		talloc_free(watch);
 		return ENOMEM;
 	}
@@ -265,6 +266,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -280,6 +283,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:38:38 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:38:38 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434933.687795 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLa-0000MG-5i; Tue, 01 Nov 2022 15:38:38 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434933.687795; Tue, 01 Nov 2022 15:38:38 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLa-0000M8-2W; Tue, 01 Nov 2022 15:38:38 +0000
Received: by outflank-mailman (input) for mailman id 434933;
 Tue, 01 Nov 2022 15:38:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLY-0000Lp-Jj
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLY-0001VC-J5
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLY-00040c-I4
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=IuCpgv3KVOWQOhOSN9sYmwuQ3W7BKSdBqRTgxx07NP8=; b=wA0nKhCB8L07KiMYiGUxRJrndu
	h8Sm3dmbB2tdRdIuPfOS+JaxOzvNYp8C0wZM4Or1VSPy851sD6s5csz0rj4DDuvUIt2vpsfSYc4eR
	pUAKNt/IDVj7/zfaH7uUKbep++Iy/7ac+8dlLsHNy7Qj33INsTMW8BewK1AWFCZ9x4tc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: add memory accounting for nodes
Message-Id: <E1optLY-00040c-I4@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:38:36 +0000

commit 7dc06ed1f2ab191ec03e892329be90ecdcd764c8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    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        | 139 ++++++++++++++++++++++++++++++---
 tools/xenstore/xenstored_core.h        |  13 +++
 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 eca04e734a..2c0f8fd99b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -496,6 +496,117 @@ static void initialize_fds(int sock, int *p_sock_pollfd_idx,
 	}
 }
 
+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.
@@ -549,9 +660,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. */
@@ -615,12 +732,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;
 }
 
@@ -1119,7 +1233,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;
 	}
@@ -1182,6 +1296,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;
 
@@ -1190,17 +1305,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);
 
 	/*
@@ -1252,7 +1367,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;
 			}
 		}
@@ -2075,7 +2190,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);
 		}
 	}
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 4e53072e63..521bc80384 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -141,6 +141,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 */
@@ -163,6 +168,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. */
@@ -258,6 +266,11 @@ extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
 
+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);
 
 #endif /* _XENSTORED_CORE_H */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 778b7e439c..c1beb40a3d 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;
 
@@ -292,6 +295,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
@@ -416,11 +421,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;
@@ -431,7 +436,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);
@@ -459,7 +464,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);
@@ -503,6 +508,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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:38:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:38:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434934.687799 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLj-0000Px-9Z; Tue, 01 Nov 2022 15:38:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434934.687799; Tue, 01 Nov 2022 15:38:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLj-0000Pp-6q; Tue, 01 Nov 2022 15:38:47 +0000
Received: by outflank-mailman (input) for mailman id 434934;
 Tue, 01 Nov 2022 15:38:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLi-0000Pi-Ma
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLi-0001VM-Lz
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLi-00041J-LT
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=p/JmPHozpZLe2HfzdSDW7iLifBPMRVp7lZA/8W5/ivw=; b=5aTpTwkkCz++LnqovJ1OcwEncR
	SPq7erQYoAqTjq7YAsx2N2bwPslYhG202KdQdxaQFmygsaAAtx7GqZCOfehGD7WtfCRTPbg3kIQzZ
	4gmd9z3OTTonHqYxB0MArQ/jWP1/ZsAJtVw02cFOEAg4qyrLl2qZ3tPcXk/gUNWyGneo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: add exports for quota variables
Message-Id: <E1optLi-00041J-LT@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:38:46 +0000

commit 146b9544fbef9d5d2e7a8e072d3d40d5065294f2
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 1da16d5990b5f7752657fca3e948f735177ea9ad)
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 521bc80384..5abf06c21c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -231,6 +231,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index c1beb40a3d..6e29118c80 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static void set_tdb_key(const char *name, TDB_DATA *key)
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 7118c30e8c..19d0fb01b1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:38:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:38:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434935.687803 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLt-0000T3-B9; Tue, 01 Nov 2022 15:38:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434935.687803; Tue, 01 Nov 2022 15:38:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optLt-0000Ss-8Q; Tue, 01 Nov 2022 15:38:57 +0000
Received: by outflank-mailman (input) for mailman id 434935;
 Tue, 01 Nov 2022 15:38:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLs-0000Sm-QL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLs-0001VW-Ph
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optLs-00043W-Ob
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:38:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=WhEcTR3rR4HSYV652awTAofiGvUA0IUAqMMSvDM01cg=; b=Rrix98lojMFU+VWwjKKadfCdml
	0BCkFmtRtccccAcBxPlIKQ2dHr4okeGZD4Xm1Bk3Po6YDL/ZwUZ1/1JTSjke5wkEiXgwYCG9A+6Mg
	hHpSP2K/xGQnbE2GQy7NNXIyqtQ94fs/S/sGUcCUaJ5FlugEC4Y9zEJZBfLNyvJM5B+Y=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1optLs-00043W-Ob@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:38:56 +0000

commit 63dc2a18f8ff098efbae76dde431938d5be20462
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 32969eb3fe..0dbac442d7 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -346,6 +346,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 715e0d2a9e..454fe9d5ab 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "utils.h"
@@ -77,6 +78,114 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
 {
@@ -136,6 +245,8 @@ static struct cmd_s cmds[] = {
 	{ "logfile", do_control_logfile, "<file>" },
 	{ "memreport", do_control_memreport, "[<file>]" },
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 2b23452e0c..4b2da302c2 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -352,6 +353,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 3a8c6bab48..e013a9991c 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -90,6 +90,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:39:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:39:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434936.687807 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optM3-0000W6-Ch; Tue, 01 Nov 2022 15:39:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434936.687807; Tue, 01 Nov 2022 15:39:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optM3-0000Vy-A5; Tue, 01 Nov 2022 15:39:07 +0000
Received: by outflank-mailman (input) for mailman id 434936;
 Tue, 01 Nov 2022 15:39:07 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optM3-0000Vs-0g
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:07 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optM3-0001Vs-01
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:07 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optM2-00044Z-S6
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=iomBe1rX8QLBvGy/8dHUTKgmyLjbDwS02Bx96YCfp/Y=; b=jkTvgbByx7MMTghYV8BvxWxKNh
	Qh8BEGOlZCc2kbK73u8usAxSnRwupp8eFxp00dopvizSwad18/RxtRqz2PQ0E9TTFpci0Sy+bdnym
	gm5yCbg8I+R/Ac9F0ixA40Tc2iCRxwG/zJ9ggAl8TbiXbLglS2R4MwcN9KWy6rb7Ks2M=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1optM2-00044Z-S6@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:39:06 +0000

commit d71e4eca23e1b545e39a1418f07cbdece3fa0c4c
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 84734955d4bf629ba459a74773afcde50a52236f)
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index f574397a4c..96c125a969 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -22,9 +22,9 @@ let xs_daemon_socket_ro = Paths.xen_run_stored ^ "/socket_ro"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:39:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:39:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434937.687811 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optME-0000Yy-Er; Tue, 01 Nov 2022 15:39:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434937.687811; Tue, 01 Nov 2022 15:39:18 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optME-0000Yr-Bc; Tue, 01 Nov 2022 15:39:18 +0000
Received: by outflank-mailman (input) for mailman id 434937;
 Tue, 01 Nov 2022 15:39:17 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMD-0000Yf-3m
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:17 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMD-0001Vz-37
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:17 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMD-00045M-2I
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:17 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=u6RYve90BAvDrQxsFgFtXlZ6Mxw5Xaql70ULwl5NHNo=; b=LGvYMzxvc9oo4yY/oARUwkynCb
	cRmI/v9mHe58HMdeZ1wN8F+btLHg/oNzkWX4ERWx8q93b2jJZTj1LMbxiFzLH6ud9pI0SFbmqbhZY
	c2BuhwJlRRcv0ZpY0UQDvXBscLJO0eYO8K/Cnry302QBCNW1zvPBp37dnbYuadDel0b0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1optMD-00045M-2I@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:39:17 +0000

commit c084ee8e5834a33fba8e03fe9bcd1e1ebe03b09d
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    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 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff)
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 3ab09c6ce9..3279b19b1b 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:39:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:39:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434938.687815 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optMO-0000cc-Ft; Tue, 01 Nov 2022 15:39:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434938.687815; Tue, 01 Nov 2022 15:39:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optMO-0000cV-DE; Tue, 01 Nov 2022 15:39:28 +0000
Received: by outflank-mailman (input) for mailman id 434938;
 Tue, 01 Nov 2022 15:39:27 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMN-0000cE-6Y
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:27 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMN-0001W7-5v
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:27 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMN-00046H-5J
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:27 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0FoajUvUglwfrGcV/X8ahLeGjqWO+z1KqWBNSENSgtQ=; b=V+WkEii0BBDl551PGK+vfOIMIh
	UXTH/pPfizhJ3ZXsjpm8Is+TIg18y8osk4qzlUOVDKD/lihjrTt9OABJmSj0j5a39VqiItLIb/LML
	nuHD0Qm/9znFfmVbddB5JXUBeiZTxuXuUM18NyNT0f+KjXYmoMtC+wddkPLwHXFNp4hg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml: GC parameter tuning
Message-Id: <E1optMN-00046H-5J@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:39:27 +0000

commit bc93157f7b3b571b44bce0ecf7328c82c7aca78b
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 4a8bacff20b857ca0d628ef5525877ade11f2a42)
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 96c125a969..1a5d2f34a6 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -26,6 +26,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 369b5036f4..0b6343dfc7 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -229,6 +230,67 @@ let to_file store cons file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -238,6 +300,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:39:38 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:39:38 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434940.687818 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optMY-0000gT-Iv; Tue, 01 Nov 2022 15:39:38 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434940.687818; Tue, 01 Nov 2022 15:39:38 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optMY-0000gK-GF; Tue, 01 Nov 2022 15:39:38 +0000
Received: by outflank-mailman (input) for mailman id 434940;
 Tue, 01 Nov 2022 15:39:37 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMX-0000gA-9U
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:37 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMX-0001WU-8m
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:37 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMX-000476-8D
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:37 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=demCTqGcm8H2pbz5jcpdxkSGPH5geXCvPfaiheUrkec=; b=YnnsS2L51f2tAF2AZlJwY2ZEUG
	FIyg5nDDWQJ+deDZQ56iRzAXJe7gkAlds4zpf4VKL1xRO0MUWenrCV+GGitV6e4G/9yVNv3pirkx9
	7OnfWuDQwNgonwJVKO+Vyz2Y4LX7o+to1iXkrkyBuhSl6ymewJLPGlpesqpiY/frnyBU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml/libs/xb: hide type of Xb.t
Message-Id: <E1optMX-000476-8D@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:39:37 +0000

commit 0135300160627cd502d9179ab79da1c631dca6f0
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Fri Jul 29 18:53:29 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml/libs/xb: hide type of Xb.t
    
    Hiding the type will make it easier to change the implementation
    in the future without breaking code that relies on it.
    
    No functional change.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba)
---
 tools/ocaml/libs/xb/xb.ml           | 3 +++
 tools/ocaml/libs/xb/xb.mli          | 9 ++-------
 tools/ocaml/xenstored/connection.ml | 4 +---
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 104d319d77..8404ddd8a6 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out
 let input_len con = Queue.length con.pkt_in
 let has_in_packet con = Queue.length con.pkt_in > 0
 let get_in_packet con = Queue.pop con.pkt_in
+let has_partial_input con = match con.partial_in with
+	| HaveHdr _ -> true
+	| NoHdr (n, _) -> n < Partial.header_size ()
 let has_more_input con =
 	match con.backend with
 	| Fd _         -> false
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 3a00da6cdd..794e35bb34 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,13 +66,7 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
-type t = {
-  backend : backend;
-  pkt_in : Packet.t Queue.t;
-  pkt_out : Packet.t Queue.t;
-  mutable partial_in : partial_buf;
-  mutable partial_out : string;
-}
+type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
 val queue : t -> Packet.t -> unit
@@ -97,6 +91,7 @@ val has_output : t -> bool
 val peek_output : t -> Packet.t
 val input_len : t -> int
 val has_in_packet : t -> bool
+val has_partial_input : t -> bool
 val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index daf8d804f7..70c4348552 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -125,9 +125,7 @@ let get_perm con =
 let set_target con target_domid =
 	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
 
-let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with
-	| Xenbus.Xb.Xenmmap _ -> true
-	| _ -> false
+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
 let send_reply con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:39:48 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:39:48 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434941.687824 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optMi-0000jE-LD; Tue, 01 Nov 2022 15:39:48 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434941.687824; Tue, 01 Nov 2022 15:39:48 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optMi-0000j6-Ho; Tue, 01 Nov 2022 15:39:48 +0000
Received: by outflank-mailman (input) for mailman id 434941;
 Tue, 01 Nov 2022 15:39:47 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMh-0000iv-Cc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:47 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMh-0001WY-Bt
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:47 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMh-00047r-B8
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:47 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=jPnqn7Mza0AfIQjJ56OEg66A8z8EQ7JgOvAZU3+unzc=; b=jftLm44FPcLMaC9I4cJ2qIPVAI
	aP9JPBOHar7Jp9ss0EMNfJipDSwbvDNu1cS48uEsXT0uBw2O1iZX8Rsz+lcnzh9ZrLJd7/3V3vmxW
	WTTnrq+eYAxZahvTYLfaLGh0T+kcp/uhVe00bNf9EuyBwd8yFfwU8OuG2Vo1zRm4u2QY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1optMh-00047r-B8@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:39:47 +0000

commit c3c5f0aa4684d436accc314f69a585e8bc7fffea
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c0a86a462721008eca5ff733660de094d3c34bc7)
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  2 --
 tools/ocaml/xenstored/process.ml    | 12 ++++++------
 5 files changed, 18 insertions(+), 39 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 70c4348552..ace2aa5b4f 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,8 +277,6 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 3279b19b1b..72629ee38b 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -570,16 +570,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -589,8 +590,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:39:58 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:39:58 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434942.687827 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optMs-0000mq-Lz; Tue, 01 Nov 2022 15:39:58 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434942.687827; Tue, 01 Nov 2022 15:39:58 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optMs-0000mi-JN; Tue, 01 Nov 2022 15:39:58 +0000
Received: by outflank-mailman (input) for mailman id 434942;
 Tue, 01 Nov 2022 15:39:57 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMr-0000mV-FY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:57 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMr-0001Wc-Et
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:57 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optMr-000494-E5
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:39:57 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5xDi7MGkBElY7nyUmZ3jj1/Qw7ahUKzoc1Hu113rOM0=; b=3b4M++B1pnSr4X+ybqmj6BBLmI
	rjP8GftoxJSGSaNfigHKK9WFrbrn0Y2/R+IfJ6wmqu0hHRsV7sjggJ9Zy648G9D6UkY1cWaDge4CS
	A+17B/q9Ad3T/zcNx2ZjkRw06AHqF+bKrIOtvXWgS3EEeZv2xJ9O8Wa+8/mhhXtZgtnE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1optMr-000494-E5@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:39:57 +0000

commit 723e24871833406093b6a8e2e5b9a3d8de2e5e04
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 19171fb5d888b4467a7073e8febc5e05540956e9)
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:40:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:40:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434943.687832 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optN2-0001bv-Or; Tue, 01 Nov 2022 15:40:08 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434943.687832; Tue, 01 Nov 2022 15:40:08 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optN2-0001bU-Kx; Tue, 01 Nov 2022 15:40:08 +0000
Received: by outflank-mailman (input) for mailman id 434943;
 Tue, 01 Nov 2022 15:40:07 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optN1-0001YM-In
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:07 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optN1-0001Wt-I1
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:07 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optN1-0004Af-HL
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:07 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=gciH4tLCkgJerWPBkf5n/zI+U+7Os6x7MfYbQmJDodA=; b=Lp8Y1JRGJIl6wiUeyAH9iJYz2H
	dnKviIYM+UARw08jWKTh+eskTSnudVOQTZkfpjYQzi/BCOLz/w3SRX98UWsDS9BDuypngcD48VJ2R
	bdC+1qTOWux18QoJq1zZJ8zV5bJRCfm6iFj2h2YIlspXAiP/03t7szrU91wfrhhkWG0g=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1optN1-0004Af-HL@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:40:07 +0000

commit 0252d044fcd4320450d3cef6c13492ef2faec2a1
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96)
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index ace2aa5b4f..9aad451a2d 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -279,6 +407,7 @@ let get_transaction con tid =
 let do_input con = Xenbus.Xb.input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -286,7 +415,7 @@ let peek_output con = Xenbus.Xb.peek_output con.xb
 let do_output con = Xenbus.Xb.output con.xb
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 7efdf3e5e0..39190c19ec 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: (string, Connection.watch list) Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd _can_write =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -196,3 +215,13 @@ let debug cons =
 	let anonymous = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.anonymous [] in
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
+
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 1a5d2f34a6..9e52367094 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 72629ee38b..d2a3ba064e 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -56,7 +56,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -66,8 +66,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -99,6 +100,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -207,7 +222,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -366,7 +381,7 @@ let do_watch con t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -397,7 +412,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -565,7 +580,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -593,6 +609,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 0b6343dfc7..4f8fab2dd1 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -102,6 +102,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:40:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:40:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434944.687834 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNC-0001h9-Rp; Tue, 01 Nov 2022 15:40:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434944.687834; Tue, 01 Nov 2022 15:40:18 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNC-0001h1-PC; Tue, 01 Nov 2022 15:40:18 +0000
Received: by outflank-mailman (input) for mailman id 434944;
 Tue, 01 Nov 2022 15:40:17 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNB-0001gr-MG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:17 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNB-0001X5-Le
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:17 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNB-0004Bk-KY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:17 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=KVMYdO6vxW26bexNM2NNzB4sblJosmzLfrTgx9v8reo=; b=xL+TjWkefCR9WzfLPKXcDdKdYU
	FUDQzEfez/J6TyrKc4saMIYBBoedfo0FrOMiflqE//M2WxolYX3Nkjnuw41vtgb9ajX6pG61O6YY1
	CZPsl10+LRrQDc34GL8WE2jIn5t6hkgZ5W/zE0qelGbdqJajyegaEyIYUKMKQOA9W4Lg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1optNB-0004Bk-KY@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:40:17 +0000

commit e30f7c6b6b8e08ec4dfc7ca9ffdc556e597182c4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c7bc20d8d123851a468402bbfc9e3330efff21ec)
---
 SUPPORT.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/SUPPORT.md b/SUPPORT.md
index 3f4a01101e..2db341c1d8 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -149,6 +149,17 @@ Output of information in machine-parseable JSON format
 
     Status: Supported
 
+## Xenstore
+
+### C xenstored daemon
+
+    Status: Supported
+
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+
 ## Toolstack/3rd party
 
 ### libvirt driver for xl
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:40:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:40:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434946.687839 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNM-0001k2-Ta; Tue, 01 Nov 2022 15:40:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434946.687839; Tue, 01 Nov 2022 15:40:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNM-0001jv-Qo; Tue, 01 Nov 2022 15:40:28 +0000
Received: by outflank-mailman (input) for mailman id 434946;
 Tue, 01 Nov 2022 15:40:27 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNL-0001ji-PN
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:27 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNL-0001XF-Of
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:27 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNL-0004CV-O5
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:27 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NRYFPczt3InrvXDqDwgQNDRZL3Be+/J6T/2FQDludO0=; b=CEtsIaTJnQxjAepim8JgACcZE1
	i1vEkX+KNqdzGWT+I33IUF/IRtqNKqqzWZ6QmAIwZ6nUmvprvCF2Ou5NNxL3yrf+83qEscu7jcazK
	ubWWZL9OtajE08BGWVvH24sA5hRLWtrAe3DbbBxFBkv4CWyet3ECZ/wHu2x+VaXJcTls=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1optNL-0004CV-O5@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:40:27 +0000

commit 2fdf8740b9f47e424952869406261962db428b97
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2a587de219cc0765330fbf9fac6827bfaf29e29b)
---
 tools/xenstore/xenstored_control.c     | 27 ++++++------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 27 +++++++-----
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 115 insertions(+), 74 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 454fe9d5ab..3585d7c695 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -30,11 +30,11 @@
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -46,7 +46,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -63,7 +63,7 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -162,7 +162,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -174,7 +174,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -186,7 +186,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 	return EINVAL;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -225,7 +225,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -237,7 +237,7 @@ static int do_control_print(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -250,7 +250,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd, len = 0;
@@ -286,7 +286,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	int num;
 	int cmd;
@@ -298,7 +299,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (num < 1)
 		return EINVAL;
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) != num)
@@ -306,7 +307,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 
 	for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++)
 		if (streq(vec[0], cmds[cmd].cmd))
-			return cmds[cmd].func(in, conn, vec + 1, num - 1);
+			return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 
 	return EINVAL;
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index 207e0a6fa3..faa955968d 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,4 +16,5 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2c0f8fd99b..d6bbb532fb 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1145,11 +1145,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1158,7 +1160,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1170,7 +1172,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1197,7 +1200,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1213,11 +1216,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1397,7 +1402,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1411,12 +1417,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1427,18 +1433,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1446,10 +1453,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 		/* No permissions? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1547,22 +1554,23 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1577,7 +1585,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1587,13 +1595,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1606,7 +1616,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1623,7 +1634,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1638,7 +1649,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1673,7 +1684,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1681,7 +1692,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1754,6 +1766,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	if ((unsigned int)type >= XS_TYPE_COUNT || !wire_funcs[type].func) {
 		eprintf("Client unknown operation %i", type);
@@ -1774,10 +1787,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 4b2da302c2..3e2f49985a 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -337,7 +337,7 @@ bool domain_can_write(struct connection *conn)
 	return ((intf->rsp_prod - intf->rsp_cons) != XENSTORE_RING_SIZE);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -479,7 +479,8 @@ static void domain_conn_reset(struct domain *domain)
 }
 
 /* domid, mfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -558,7 +559,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -605,7 +607,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -620,7 +623,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -635,7 +639,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -643,18 +648,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -675,7 +679,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index e013a9991c..732eb8fa75 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -22,25 +22,32 @@
 void handle_event(void);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(void);
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6e29118c80..cd592845e7 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -487,7 +487,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -500,8 +501,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -548,7 +549,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -564,8 +566,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	list_del(&trans->list);
 	conn->transaction_started--;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 19d0fb01b1..13627ce972 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -184,7 +184,7 @@ static int destroy_watch(void *_watch)
 	return 0;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -200,7 +200,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 		/* check if valid event */
 	} else {
 		relative = !strstarts(vec[0], "/");
-		vec[0] = canonicalize(conn, in, vec[0]);
+		vec[0] = canonicalize(conn, ctx, vec[0]);
 		if (!vec[0])
 			return ENOMEM;
 		if (!is_valid_nodename(vec[0]))
@@ -250,7 +250,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -258,7 +259,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 03094374f3..40455dff5d 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:40:38 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:40:38 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434948.687843 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNW-0001n7-VK; Tue, 01 Nov 2022 15:40:38 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434948.687843; Tue, 01 Nov 2022 15:40:38 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNW-0001mz-SU; Tue, 01 Nov 2022 15:40:38 +0000
Received: by outflank-mailman (input) for mailman id 434948;
 Tue, 01 Nov 2022 15:40:37 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNV-0001mt-SW
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:37 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNV-0001XZ-Rr
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:37 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNV-0004Dh-Qy
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:37 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=O0gqk7RqbtYmaI+Hw3sCGxsNLO5+yjr7iTKVkJXceco=; b=Xf9jZR7yRZnLqLogkCPO0wCpcI
	Lgwwl1pSRyK3FPXZJqCi3aiZwNOwsvQMhhoJHuRc3aBMQPuqrad5Wz6NEKzDXEXZyY5/ueQCnzrTW
	aCiTQCm4Go03rF0qj5MUjhR7RJboZGSamki58pdwHgMGW4IN/Er9SEE98xHTIxkTrJMk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: fix checking node permissions
Message-Id: <E1optNV-0004Dh-Qy@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:40:37 +0000

commit e6655e8f25e4ebf3d3cabac2430c8d5ba33a15a5
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ab128218225d3542596ca3a02aee80d55494bef8)
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index d6bbb532fb..25064427be 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1640,6 +1640,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3e2f49985a..43fc2c4879 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -866,7 +866,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -874,20 +873,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -900,8 +917,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -918,8 +933,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 732eb8fa75..bab405209e 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,6 +65,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:40:49 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:40:49 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434949.687846 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNh-0001rx-2Y; Tue, 01 Nov 2022 15:40:49 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434949.687846; Tue, 01 Nov 2022 15:40:49 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNg-0001rq-Vv; Tue, 01 Nov 2022 15:40:48 +0000
Received: by outflank-mailman (input) for mailman id 434949;
 Tue, 01 Nov 2022 15:40:48 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNg-0001qq-12
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:48 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNg-0001Xf-0K
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:48 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNf-0004Et-U6
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:47 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=E3UL3QzIKMboY/4/U3bmwUUffoM5NxnihWksO1MmSYE=; b=Zv2+OBJM7IgAyI4OqW63rVyHtQ
	Cs3onoDlpJCWNw7vjLkp6QQiJDXfKsranuOvoSU6KgqWn/Z2sas95wRlvv8YKHI2pDP61DYKhXPcP
	pCdmhEN8cbl8IrRrMMhqRmes33ICsdebMkYsqx4SJWqIbYbv2E9YrhkV2oOhYene0Xrs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1optNf-0004Et-U6@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:40:47 +0000

commit b97e59f10d6f16b329ee95979cbc1b504bab076d
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 110 ++++++++++++++++++++++++++--------------
 1 file changed, 72 insertions(+), 38 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 25064427be..8ae0842ca3 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1252,57 +1252,91 @@ static char *basename(const char *name)
 	return strrchr(name, '/') + 1;
 }
 
-static struct node *construct_node(struct connection *conn, const void *ctx,
-				   const char *name)
+static int add_child(const void *ctx, struct node *parent, const char *name)
 {
 	const char *base;
 	unsigned int baselen;
-	struct node *parent, *node;
-	char *children, *parentname = get_parent(ctx, name);
-
-	if (!parentname)
-		return NULL;
+	char *children;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
-
-	/* Add child to parent. */
 	base = basename(name);
 	baselen = strlen(base) + 1;
 	children = talloc_array(ctx, char, parent->childlen + baselen);
 	if (!children)
-		goto nomem;
+		return ENOMEM;
 	memcpy(children, parent->children, parent->childlen);
 	memcpy(children + parent->childlen, base, baselen);
 	parent->children = children;
 	parent->childlen += baselen;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
-
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
-
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
+	return 0;
+}
+
+static struct node *construct_node(struct connection *conn, const void *ctx,
+				   const char *name)
+{
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
+
+	if (!parentname)
+		return NULL;
+
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
+
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
+
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
+
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
+
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:40:59 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:40:59 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434952.687851 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNr-0001xG-3o; Tue, 01 Nov 2022 15:40:59 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434952.687851; Tue, 01 Nov 2022 15:40:59 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optNr-0001x8-1A; Tue, 01 Nov 2022 15:40:59 +0000
Received: by outflank-mailman (input) for mailman id 434952;
 Tue, 01 Nov 2022 15:40:58 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNq-0001wy-3z
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:58 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNq-0001Xj-3J
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:58 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optNq-0004Fk-2d
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:40:58 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Lvzap6iGAbyzzFan6xlkRvkYv9jt7a81zbe1qvUaefI=; b=hUntx0oEYjzL0Cu58BhTPNe+2z
	qGDVhsN9WKXZGzAOJonn7GdjHOrhCls9EnhF51nSdfKhd/5WjHl1VC9p4jWCPSEFDNMg+ffJULacv
	E/W2l92TcrwBQEELIUucZrNFuqtoalrobL/iHA6/ip2lXCwmbWgho7tucvUlZbdNWleQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1optNq-0004Fk-2d@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:40:58 +0000

commit e2b7fa7508d7bff94ea72def2bb85c264065b2c0
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4)
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8ae0842ca3..006af15765 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1503,15 +1503,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1521,7 +1521,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2123,6 +2125,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2171,12 +2184,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2193,11 +2201,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:41:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:41:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434953.687855 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optO1-0001zw-5m; Tue, 01 Nov 2022 15:41:09 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434953.687855; Tue, 01 Nov 2022 15:41:09 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optO1-0001zk-2l; Tue, 01 Nov 2022 15:41:09 +0000
Received: by outflank-mailman (input) for mailman id 434953;
 Tue, 01 Nov 2022 15:41:08 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optO0-0001zZ-7A
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:08 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optO0-0001Y1-6O
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:08 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optO0-0004GY-5c
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:08 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=deHcShzU7y3FzXNdfVO2V072sbSvS3aLP5lKcFIKUHs=; b=dxTmMc5l1EZfWY8r1AlEmFNMwR
	7C3L5UE/njJoBK8wHn3NcA/puRUZ/OjgVeYBqt1Ep0HFsdx2/Q+b813VrKVYxUgiyZiEeWaN6HL+q
	JT7l9Yxm3ezhhHXMkN1bhngZ7PBSpnSmljJa+SK816jkd2ruNx0rmqp6r3yCl15htcCc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: add generic treewalk function
Message-Id: <E1optO0-0004GY-5c@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:41:08 +0000

commit d816b470e0225f2018d011a92e0ebb03595a9085
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d7c5d19bc27492360196e7dad2b227908564fff)
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 006af15765..c3b2a42214 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1731,6 +1731,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2103,18 +2232,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2170,7 +2287,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 5abf06c21c..fc9882ac37 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -167,6 +167,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -278,6 +279,45 @@ int do_tdb_delete(struct connection *conn, TDB_DATA *key,
 
 void conn_free_buffered_data(struct connection *conn);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:41:19 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:41:19 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434954.687859 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOB-00022n-6x; Tue, 01 Nov 2022 15:41:19 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434954.687859; Tue, 01 Nov 2022 15:41:19 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOB-00022f-4F; Tue, 01 Nov 2022 15:41:19 +0000
Received: by outflank-mailman (input) for mailman id 434954;
 Tue, 01 Nov 2022 15:41:18 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOA-00022Y-9v
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:18 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOA-0001YI-9J
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:18 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOA-0004H3-8e
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:18 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=39ngYvkV35BcEa6wLgrww3t8FwZPnSR2pu7jk4uQU5g=; b=fpzu9h9NWa1V7535ivgRq+hW8P
	gO/71BvD4gFl9qPRE4LqVjbP23Ic9hCMtEtH7632k8LHLhilVfNuiGjLyk2q4jCD2k99fpFEaErpv
	qypeRCOf14g/xzTdmTqirT9G4pWDlufTjxde/53Cuz7Y69qbhdjduzLDlPo2a8lN0aQo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: simplify check_store()
Message-Id: <E1optOA-0004H3-8e@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:41:18 +0000

commit ba1cff4b1be983ea7ec55a994a3adc8b40903800
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 70f719f52a220bc5bc987e4dd28e14a7039a176b)
---
 tools/xenstore/xenstored_core.c | 43 ++++++++++++++---------------------------
 1 file changed, 15 insertions(+), 28 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c3b2a42214..877e88560c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2275,46 +2275,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2324,19 +2312,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:41:30 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:41:30 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434956.687862 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOM-00026P-8S; Tue, 01 Nov 2022 15:41:30 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434956.687862; Tue, 01 Nov 2022 15:41:30 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOM-00026I-5k; Tue, 01 Nov 2022 15:41:30 +0000
Received: by outflank-mailman (input) for mailman id 434956;
 Tue, 01 Nov 2022 15:41:28 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOK-000268-D7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:28 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOK-0001YV-CN
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:28 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOK-0004Hh-Be
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:28 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=aKZWYW+aXNeFIaIWxCyw2XSm2UWTttOxFVOje6aHd+U=; b=r9Nxm8SvJLQlPcbCODgUC0Mw+I
	W/mnxfxmM1F2mlxHARWAlBH0UCdkm8lz8vBUwdoFxlZLDVdpKZ3yxVAGKtr65QqXtAzZGYYCWeKEG
	OjLR7I9ljyIbnqX73mOCT9ePpx4tUYiuW666dQAC94Ul9kwr0PG+0g+tyroU0bKPQRSQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: use treewalk for check_store()
Message-Id: <E1optOK-0004Hh-Be@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:41:28 +0000

commit 1cfbd2567b68e3e021a963d6f45f6adfa359c8d4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 877e88560c..fb25f72017 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2242,18 +2242,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2267,70 +2255,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
-
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
+	struct hashtable *reachable = arg;
 
-			childnode = read_node(NULL, childname, childname);
-
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2379,24 +2326,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char * root = talloc_strdup(NULL, "/");
-	struct hashtable * reachable =
-		create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
+
+	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
 		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:41:40 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:41:40 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434957.687866 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOW-00029k-DF; Tue, 01 Nov 2022 15:41:40 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434957.687866; Tue, 01 Nov 2022 15:41:40 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOW-00029c-Ac; Tue, 01 Nov 2022 15:41:40 +0000
Received: by outflank-mailman (input) for mailman id 434957;
 Tue, 01 Nov 2022 15:41:38 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOU-00029V-GP
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:38 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOU-0001aT-Fg
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:38 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOU-0004IW-Eo
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:38 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=skQUgFwQTXBY4+mTrQDnnBAdNYvpES8JwroOTMG2uCY=; b=UPm2ivuGWBDHJP2rMItT8A/GlA
	l//dM0YqsPKN9HpCNiH3F+n50b4FRBFkHogIEY+nUkHXwyF4f6AHJ56tHjec89E9jiIwtuexphd7k
	Jsa7z8H4Wd+T9L9RPCLmXn4N4ca/eysYA1LWMMuvIVqI+WUzaWfw/UpMuK3aOVkpGsJ4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1optOU-0004IW-Eo@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:41:38 +0000

commit 8c8a5b3905d4bd6d2646ddaf00a424bde62289ef
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ea16962053a6849a6e7cada549ba7f8c586d85c6)
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index fb25f72017..9655af4c01 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1231,21 +1231,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1514,69 +1499,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1584,9 +1559,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1621,7 +1608,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:41:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:41:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434958.687871 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOg-0002CG-Ez; Tue, 01 Nov 2022 15:41:50 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434958.687871; Tue, 01 Nov 2022 15:41:50 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOg-0002C8-CB; Tue, 01 Nov 2022 15:41:50 +0000
Received: by outflank-mailman (input) for mailman id 434958;
 Tue, 01 Nov 2022 15:41:48 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOe-0002Bs-Jc
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:48 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOe-0001aX-Iv
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:48 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOe-0004Ix-I9
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:48 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=MB+bTwAqIBs7N9CYBXl8k0l5xtTvTqDxxO98DkjktGs=; b=1lQcrCPFWJEpOn7tXcKPAPxpv3
	/NlD7wy4tWUzaGZciMlUxWfBxnEUtNZkk8Z7i7wSISJSUqQm/icGgk7MmJ5DbLSOKqe23ndpc+19G
	chUJvtGLYxNdCLUXmI2x4LHlhEGu2cejFfpj9KSaXtwBAZhBOyj8dEAshsFh2+znfrEE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1optOe-0004Ix-I9@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:41:48 +0000

commit a8922c661c2e2436c0d60da3ab9b12b47f308a92
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 755d3f9debf8879448211fffb018f556136f6a79)
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 85 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 81 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9655af4c01..7eb698e1fc 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -76,6 +76,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -662,7 +663,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -705,7 +706,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1546,7 +1547,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1608,7 +1609,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2461,6 +2462,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2484,6 +2487,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 	{ NULL, 0, NULL, 0 } };
@@ -2558,7 +2562,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2594,6 +2598,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index fc9882ac37..ec24c27ac2 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -204,6 +204,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(void);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 void check_store(void);
@@ -242,6 +245,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 43fc2c4879..116b78c0f6 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -204,10 +204,65 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		key.dptr = (char *)node->name;
+		key.dsize = strlen(node->name);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -842,15 +897,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -911,23 +966,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -945,15 +988,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1072,7 +1115,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index bab405209e..5bd253395d 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,7 +64,7 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:42:00 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:42:00 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434959.687875 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOq-0002FT-GN; Tue, 01 Nov 2022 15:42:00 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434959.687875; Tue, 01 Nov 2022 15:42:00 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optOq-0002FL-Dh; Tue, 01 Nov 2022 15:42:00 +0000
Received: by outflank-mailman (input) for mailman id 434959;
 Tue, 01 Nov 2022 15:41:58 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOo-0002FE-Mh
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:58 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOo-0001ad-Lz
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:58 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOo-0004Je-LJ
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:41:58 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=1S2rC59PrtCgfCqyOLt+uo0yt0949fHS5zSozY4Blro=; b=MViYQ2Grg7OrdjvZEJTZDcJe8l
	ePNJ32vAGbqbsYFjPprMO2al4nfLJfPInFifVmYHR4H4Vp4+VPB9cVb4BTUctQtI6E4ElXvh1I8Vt
	AMORDyOjdmZ3jrbImmDnMV9g+7YnKNPKxOC2YGKw+Q9AB/Reoha9lmDzq9C3i7lLzFmM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: make the internal memory data base the default
Message-Id: <E1optOo-0004Je-LJ@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:41:58 +0000

commit 145871612f70aefd433c5933bc9ebe5dfb888138
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d174fefa90487ddd25ebc618028f67b2e8a1f795)
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index adb8408b63..b4d7ed573e 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -128,9 +128,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom = xc_dom_allocate(xch, cmdline, NULL);
     rv = xc_dom_kernel_file(dom, kernel);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 7eb698e1fc..683554ff2c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2132,7 +2132,7 @@ static void accept_connection(int sock, bool canwrite)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2461,7 +2461,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2486,7 +2487,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2562,7 +2563,8 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:Q:q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2596,7 +2598,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:42:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:42:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434960.687878 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optP0-0002JH-IC; Tue, 01 Nov 2022 15:42:10 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434960.687878; Tue, 01 Nov 2022 15:42:10 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optP0-0002J9-FD; Tue, 01 Nov 2022 15:42:10 +0000
Received: by outflank-mailman (input) for mailman id 434960;
 Tue, 01 Nov 2022 15:42:08 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOy-0002Ir-QM
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:08 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOy-0001b5-Os
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:08 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optOy-0004Ka-O8
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:08 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=4Uzr/ygRmfUCt/WuK5hJfCbRa5jsmC6eIFa5vwjRIcM=; b=fcyuk3MhP9eLA5ECM+xif2kzKT
	Pu4X/yiTjYsBm0dO0rh9LyZLbqGUQE7Q539EJruSROgDIm5ML0orhQTVnpNGgQd+IV+F+h+HzOcaR
	ojd0VdgPW093PvYwdeTYiw8NgmDqPNtwTXEsIwbWW4S77UOn12QG2cjCiBVzNiaEflzw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] docs: enhance xenstore.txt with permissions description
Message-Id: <E1optOy-0004Ka-O8@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:42:08 +0000

commit 3545d0f15efce1c053473019ea893799c13d1275
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d084d2c6dff7044956ebdf83a259ad6081a1d921)
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 0dbac442d7..d5084bcbaa 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:42:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:42:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434961.687883 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optPA-0002MS-Kt; Tue, 01 Nov 2022 15:42:20 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434961.687883; Tue, 01 Nov 2022 15:42:20 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optPA-0002MK-I7; Tue, 01 Nov 2022 15:42:20 +0000
Received: by outflank-mailman (input) for mailman id 434961;
 Tue, 01 Nov 2022 15:42:18 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optP8-0002MC-U7
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:18 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optP8-0001bI-Rw
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:18 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optP8-0004LE-R6
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:18 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=mNtX9AEETCiwh8ZEreDOAZxjo6Y2xf6ieHnTGb1AJU4=; b=EniAz/wdk8A4R+4cLv9b2BXBCg
	k8eV0MSveo6ODDEJdhyGDtj2NHomgNixx4bMO6hb5b9no4Uxs5C3nd33OB8Z+yDjcjnqf/7/MYSr/
	W8XfGxoac1Cg3vAPkNVMOPfY3gY3+1lYM0hIOWS0Ri6hLF2A968R0i+sCYEjh/H/acPI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1optP8-0004LE-R6@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:42:18 +0000

commit 94b2f97eaae17f3c49816c2f7224d5b698d28287
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit db471408edd46af403b8bd44d180a928ad7fbb80)
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 328d3a5198..d82764f60f 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -89,10 +89,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; List.iter (recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = List.rev_map walk node.children |> List.rev }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			List.rev_map walk node.children |> List.filter is_valid |> List.rev } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -446,11 +457,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:42:30 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:42:30 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434962.687887 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optPK-0002Ok-MK; Tue, 01 Nov 2022 15:42:30 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434962.687887; Tue, 01 Nov 2022 15:42:30 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optPK-0002Od-Jc; Tue, 01 Nov 2022 15:42:30 +0000
Received: by outflank-mailman (input) for mailman id 434962;
 Tue, 01 Nov 2022 15:42:29 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPI-0002OR-VY
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:28 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPI-0001bX-Uq
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:28 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPI-0004MA-UG
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:28 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=6Ps+NGuykKRt4Ru9GIFPqC/iKQRmPAWdUCVVEu6HGfQ=; b=0Z+mKqwE3LLeT8akpRVBoOn3yw
	Mk4g5uwEx3TQ1bmFUpxho0wejhpnCQgzzng+EdTv/e5I9XsY7FFwk8dLqXOX4Eiz/xsJA7frEasLX
	nREerzglKn5ckTjxd4dMleOzkcyqWWOAQLlRvNELU4o4C92hzjpH7Gm70FXv2b7BbPFg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1optPI-0004MA-UG@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:42:28 +0000

commit 29506319c6cefb370bafc20689b67a4a3523197e
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3)
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index d2a3ba064e..027252ece8 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -587,7 +587,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:42:40 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:42:40 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434963.687890 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optPU-0002RL-Nq; Tue, 01 Nov 2022 15:42:40 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434963.687890; Tue, 01 Nov 2022 15:42:40 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optPU-0002RD-LC; Tue, 01 Nov 2022 15:42:40 +0000
Received: by outflank-mailman (input) for mailman id 434963;
 Tue, 01 Nov 2022 15:42:39 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPT-0002R6-20
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:39 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPT-0001c3-1M
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:39 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPT-0004Mt-0k
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:39 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=nE2quhefrmgbTySsznI800S7o5nSUf3nWcLo2xZMqKw=; b=kKr5NHpqfc4ljDPjWl+Jn8kgNn
	/Q7QLSVPhdVM/MpT9jWH35mhFg7r/xIy3+KwZEnIL6HIVlIWmqp0BHqGj7TmSFuFBZ81xKsTgj3el
	V5l9RzkMcLjnDXqKQx8Rsn/SoLUcbS7NNYABjCPdWXBoaBwCIXtMNdf7JrPigPaoVGgo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: fix deleting node in transaction
Message-Id: <E1optPT-0004Mt-0k@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:42:39 +0000

commit 30a293fba36b438d90b802132d70020e76086058
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187)
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd592845e7..6297149986 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -424,7 +424,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Tue Nov 01 15:42:50 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 01 Nov 2022 15:42:50 +0000
Received: from list by lists.xenproject.org with outflank-mailman.434964.687894 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optPe-0002Tl-PO; Tue, 01 Nov 2022 15:42:50 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 434964.687894; Tue, 01 Nov 2022 15:42:50 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1optPe-0002Te-Ml; Tue, 01 Nov 2022 15:42:50 +0000
Received: by outflank-mailman (input) for mailman id 434964;
 Tue, 01 Nov 2022 15:42:49 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPd-0002TX-5V
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:49 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPd-0001cD-4S
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:49 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1optPd-0004NU-3g
 for xen-changelog@lists.xenproject.org; Tue, 01 Nov 2022 15:42:49 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=3td0BExllSIg3raAjIAtnyhfy7YR0z20GRgQSOr4UjI=; b=Tn3icNQWILQAYqSW3thQ+Bm4aZ
	QwiadnRaE99Pqupceou+cWOTQKr/bo9Mb1bS2nKaknFKZjHb7rv6FhAYiBp9poomNTvhzcaIxLEJ6
	g7HAd5zJOJuiDg/iKnhi2vIiXmG+SGasq767MHRDAV9OUI+594bfayI7aUzxbRcSc700=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1optPd-0004NU-3g@xenbits.xenproject.org>
Date: Tue, 01 Nov 2022 15:42:49 +0000

commit 377dbf9cea55a1976d0957c1f209b083c734c250
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff)
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 683554ff2c..1648a7ccf5 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -632,8 +632,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -746,10 +745,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6297149986..5e4780e874 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -205,25 +206,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -246,7 +242,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -265,10 +260,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -279,9 +270,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -308,7 +300,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -327,7 +319,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -339,7 +331,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -377,100 +368,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -560,6 +541,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -581,13 +563,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -661,7 +647,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -673,11 +659,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:11:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:11:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435324.688435 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1LT-00014F-Dc; Wed, 02 Nov 2022 00:11:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435324.688435; Wed, 02 Nov 2022 00:11:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1LT-000148-Am; Wed, 02 Nov 2022 00:11:03 +0000
Received: by outflank-mailman (input) for mailman id 435324;
 Wed, 02 Nov 2022 00:11:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1LS-000142-3r
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1LS-000378-33
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1LS-0007YN-20
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=vFS6aaV4EgKhgA95QJvXOouuSkAYge/7Fq0Sk8mA7xE=; b=W2u8cLtWbN2epfWD12074ZrHOv
	e3U0MQEvvixxgMXgEouCvro2+WxmwKfVudJgHm/kdClvZlCev8YOePO1M0ro2qvhQO0irJijjKIGy
	RLPPTA90xrWJcmwH+sZYqfSjMVebNRcijkTE5uW5l0i9CFPjZkWLbzLuDjk1MiFHbCME=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] x86/vmx: Revert "VMX: use a single, global APIC access page"
Message-Id: <E1oq1LS-0007YN-20@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:11:02 +0000

commit 62e7fb702db4adaa9415ac87d95e0f461e32d9ca
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Wed Aug 24 14:16:44 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    x86/vmx: Revert "VMX: use a single, global APIC access page"
    
    The claim "No accesses would ever go to this page." is false.  A consequence
    of how Intel's APIC Acceleration works, and Xen's choice to have per-domain
    P2Ms (rather than per-vCPU P2Ms) means that the APIC page is fully read-write
    to any vCPU which is not in xAPIC mode.
    
    This reverts commit 58850b9074d3e7affdf3bc94c84e417ecfa4d165.
    
    This is XSA-412 / CVE-2022-42327.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 3b5beaf49033cddf4b2cc4e4d391b966f4203471)
---
 xen/arch/x86/hvm/vmx/vmx.c         | 59 ++++++++++++++++++++++++++++----------
 xen/arch/x86/mm/shadow/set.c       |  8 ------
 xen/arch/x86/mm/shadow/types.h     |  7 -----
 xen/include/asm-x86/hvm/vmx/vmcs.h |  1 +
 xen/include/asm-x86/mm.h           | 20 +------------
 5 files changed, 46 insertions(+), 49 deletions(-)

diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index d429d76c18..3f42765313 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -66,7 +66,8 @@ boolean_param("force-ept", opt_force_ept);
 static void vmx_ctxt_switch_from(struct vcpu *v);
 static void vmx_ctxt_switch_to(struct vcpu *v);
 
-static int alloc_vlapic_mapping(void);
+static int  vmx_alloc_vlapic_mapping(struct domain *d);
+static void vmx_free_vlapic_mapping(struct domain *d);
 static void vmx_install_vlapic_mapping(struct vcpu *v);
 static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr,
                                 unsigned int flags);
@@ -77,8 +78,6 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content);
 static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content);
 static void vmx_invlpg(struct vcpu *v, unsigned long linear);
 
-static mfn_t __read_mostly apic_access_mfn = INVALID_MFN_INITIALIZER;
-
 /* Values for domain's ->arch.hvm_domain.pi_ops.flags. */
 #define PI_CSW_FROM (1u << 0)
 #define PI_CSW_TO   (1u << 1)
@@ -402,6 +401,7 @@ static int vmx_domain_initialise(struct domain *d)
         .to   = vmx_ctxt_switch_to,
         .tail = vmx_do_resume,
     };
+    int rc;
 
     d->arch.ctxt_switch = &csw;
 
@@ -411,15 +411,24 @@ static int vmx_domain_initialise(struct domain *d)
      */
     d->arch.hvm.vmx.exec_sp = is_hardware_domain(d) || opt_ept_exec_sp;
 
+    if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 )
+        return rc;
+
     return 0;
 }
 
+static void vmx_domain_relinquish_resources(struct domain *d)
+{
+    vmx_free_vlapic_mapping(d);
+}
+
 static void domain_creation_finished(struct domain *d)
 {
     gfn_t gfn = gaddr_to_gfn(APIC_DEFAULT_PHYS_BASE);
+    mfn_t apic_access_mfn = d->arch.hvm.vmx.apic_access_mfn;
     bool ipat;
 
-    if ( !has_vlapic(d) || mfn_eq(apic_access_mfn, INVALID_MFN) )
+    if ( mfn_eq(apic_access_mfn, _mfn(0)) )
         return;
 
     ASSERT(epte_get_entry_emt(d, gfn, apic_access_mfn, 0, &ipat,
@@ -2481,6 +2490,7 @@ static struct hvm_function_table __initdata vmx_function_table = {
     .cpu_up_prepare       = vmx_cpu_up_prepare,
     .cpu_dead             = vmx_cpu_dead,
     .domain_initialise    = vmx_domain_initialise,
+    .domain_relinquish_resources = vmx_domain_relinquish_resources,
     .domain_creation_finished = domain_creation_finished,
     .vcpu_initialise      = vmx_vcpu_initialise,
     .vcpu_destroy         = vmx_vcpu_destroy,
@@ -2731,7 +2741,7 @@ const struct hvm_function_table * __init start_vmx(void)
 {
     set_in_cr4(X86_CR4_VMXE);
 
-    if ( vmx_vmcs_init() || alloc_vlapic_mapping() )
+    if ( vmx_vmcs_init() )
     {
         printk("VMX: failed to initialise.\n");
         return NULL;
@@ -3305,36 +3315,55 @@ gp_fault:
     return X86EMUL_EXCEPTION;
 }
 
-static int __init alloc_vlapic_mapping(void)
+static int vmx_alloc_vlapic_mapping(struct domain *d)
 {
     struct page_info *pg;
     mfn_t mfn;
 
-    if ( !cpu_has_vmx_virtualize_apic_accesses )
+    if ( !has_vlapic(d) || !cpu_has_vmx_virtualize_apic_accesses )
         return 0;
 
-    pg = alloc_domheap_page(NULL, 0);
+    pg = alloc_domheap_page(d, MEMF_no_refcount);
     if ( !pg )
         return -ENOMEM;
 
-    /*
-     * Signal to shadow code that this page cannot be refcounted. This also
-     * makes epte_get_entry_emt() recognize this page as "special".
-     */
-    page_suppress_refcounting(pg);
+    if ( !get_page_and_type(pg, d, PGT_writable_page) )
+    {
+        /*
+         * The domain can't possibly know about this page yet, so failure
+         * here is a clear indication of something fishy going on.
+         */
+        domain_crash(d);
+        return -ENODATA;
+    }
 
     mfn = page_to_mfn(pg);
     clear_domain_page(mfn);
-    apic_access_mfn = mfn;
+    d->arch.hvm.vmx.apic_access_mfn = mfn;
 
     return 0;
 }
 
+static void vmx_free_vlapic_mapping(struct domain *d)
+{
+    mfn_t mfn = d->arch.hvm.vmx.apic_access_mfn;
+
+    d->arch.hvm.vmx.apic_access_mfn = _mfn(0);
+    if ( !mfn_eq(mfn, _mfn(0)) )
+    {
+        struct page_info *pg = mfn_to_page(mfn);
+
+        put_page_alloc_ref(pg);
+        put_page_and_type(pg);
+    }
+}
+
 static void vmx_install_vlapic_mapping(struct vcpu *v)
 {
+    mfn_t apic_access_mfn = v->domain->arch.hvm.vmx.apic_access_mfn;
     paddr_t virt_page_ma, apic_page_ma;
 
-    if ( !has_vlapic(v->domain) || mfn_eq(apic_access_mfn, INVALID_MFN) )
+    if ( mfn_eq(apic_access_mfn, _mfn(0)) )
         return;
 
     ASSERT(cpu_has_vmx_virtualize_apic_accesses);
diff --git a/xen/arch/x86/mm/shadow/set.c b/xen/arch/x86/mm/shadow/set.c
index 87e9c6eeb2..bd6c68b547 100644
--- a/xen/arch/x86/mm/shadow/set.c
+++ b/xen/arch/x86/mm/shadow/set.c
@@ -101,14 +101,6 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type)
         owner = page_get_owner(pg);
     }
 
-    /*
-     * Check whether refcounting is suppressed on this page. For example,
-     * VMX'es APIC access MFN is just a surrogate page.  It doesn't actually
-     * get accessed, and hence there's no need to refcount it.
-     */
-    if ( pg && page_refcounting_suppressed(pg) )
-        return 0;
-
     if ( owner == dom_io )
         owner = NULL;
 
diff --git a/xen/arch/x86/mm/shadow/types.h b/xen/arch/x86/mm/shadow/types.h
index 6970e7d6ea..814a401853 100644
--- a/xen/arch/x86/mm/shadow/types.h
+++ b/xen/arch/x86/mm/shadow/types.h
@@ -276,16 +276,9 @@ int shadow_set_l4e(struct domain *d, shadow_l4e_t *sl4e,
 static void inline
 shadow_put_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
 {
-    mfn_t mfn = shadow_l1e_get_mfn(sl1e);
-
     if ( !shadow_mode_refcounts(d) )
         return;
 
-    if ( mfn_valid(mfn) &&
-         /* See the respective comment in shadow_get_page_from_l1e(). */
-         page_refcounting_suppressed(mfn_to_page(mfn)) )
-        return;
-
     put_page_from_l1e(sl1e, d);
 }
 
diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h
index 03c9ccf627..8073af323b 100644
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -58,6 +58,7 @@ struct ept_data {
 #define _VMX_DOMAIN_PML_ENABLED    0
 #define VMX_DOMAIN_PML_ENABLED     (1ul << _VMX_DOMAIN_PML_ENABLED)
 struct vmx_domain {
+    mfn_t apic_access_mfn;
     /* VMX_DOMAIN_* */
     unsigned int status;
 
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index 7bdf9c2290..e1bcea57a8 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -83,7 +83,7 @@
 #define PGC_state_offlined  PG_mask(2, 6)
 #define PGC_state_free      PG_mask(3, 6)
 #define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
-/* Page is not reference counted (see below for caveats) */
+/* Page is not reference counted */
 #define _PGC_extra        PG_shift(7)
 #define PGC_extra         PG_mask(1, 7)
 
@@ -375,24 +375,6 @@ void zap_ro_mpt(mfn_t mfn);
 
 bool is_iomem_page(mfn_t mfn);
 
-/*
- * Pages with no owner which may get passed to functions wanting to
- * refcount them can be marked PGC_extra to bypass this refcounting (which
- * would fail due to the lack of an owner).
- *
- * (For pages with owner PGC_extra has different meaning.)
- */
-static inline void page_suppress_refcounting(struct page_info *pg)
-{
-   ASSERT(!page_get_owner(pg));
-   pg->count_info |= PGC_extra;
-}
-
-static inline bool page_refcounting_suppressed(const struct page_info *pg)
-{
-    return !page_get_owner(pg) && (pg->count_info & PGC_extra);
-}
-
 struct platform_bad_page {
     unsigned long mfn;
     unsigned int order;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:11:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:11:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435325.688439 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ld-00016i-HA; Wed, 02 Nov 2022 00:11:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435325.688439; Wed, 02 Nov 2022 00:11:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ld-00016a-EM; Wed, 02 Nov 2022 00:11:13 +0000
Received: by outflank-mailman (input) for mailman id 435325;
 Wed, 02 Nov 2022 00:11:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lc-00016S-7E
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lc-00037I-6T
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lc-0007Yo-5R
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8JcAMNzm/ASwUZTwPjshuD1S0T1yVxzMZ7yoG9Bm9rg=; b=B/gQGPEZADUHwFFCDFNO9ez52d
	wN66j2RIT5xP8Q2iu2gnd+tAI+AvtILQ28uQF1LPzo4yy34YChUgvY8nJcy5HfrnQidfr91SEhHfC
	ZmCSBZWChiSiwPxmDV68iHtHc0eZ3XTouQ1I8Ddbqq7dTESs+DMcC3pQIV+gWm5CzSbE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1oq1Lc-0007Yo-5R@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:11:12 +0000

commit 28ea39a4eb476f9105e1021bef1367c075feaa0b
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 1cd3cc7ea27cda7640a8d895e09617b61c265697)
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 0c8ee276f8..29947c3020 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1088,9 +1088,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -1099,7 +1098,7 @@ static int destroy_node(void *_node)
 	set_tdb_key(node->name, &key);
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -1108,7 +1107,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1130,23 +1130,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:11:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:11:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435326.688443 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ln-00019d-Ia; Wed, 02 Nov 2022 00:11:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435326.688443; Wed, 02 Nov 2022 00:11:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ln-00019W-Ft; Wed, 02 Nov 2022 00:11:23 +0000
Received: by outflank-mailman (input) for mailman id 435326;
 Wed, 02 Nov 2022 00:11:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lm-00019J-AU
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lm-00037Z-9k
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lm-0007ZE-8p
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ZnX/VF9FUvANNwM3hoHQhaeA+KDemx5EShWQpUNodEM=; b=U1Tihcjig0RapIvJcFvA9s2mjR
	7BNurnWF7FP1tLm9JcLYHd08qIzr4WwjQZBL3eJ2lePP7A/UMdZ8coHEv6iOOzY2uHDYulk9AYsIg
	AEz0JPBFhl7RSvoFfYZenVlyenzUjoJszXDA3ZGC3zbaAq4Skmluf0Wt8o+1qAg5jq6k=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1oq1Lm-0007ZE-8p@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:11:22 +0000

commit 427e86b48836a9511f57004ca367283cd85cd30f
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34)
---
 tools/xenstore/xenstored_core.c        | 23 +++++++++++++++--------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 29947c3020..e9c9695fd1 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -566,15 +566,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 unsigned int perm_for_conn(struct connection *conn,
@@ -1090,16 +1092,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	set_tdb_key(node->name, &key);
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 07d861d924..0004fa848c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -155,6 +155,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd07fb0f21..faf6c930e4 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:11:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:11:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435328.688447 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Lx-0001CS-KI; Wed, 02 Nov 2022 00:11:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435328.688447; Wed, 02 Nov 2022 00:11:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Lx-0001CK-Ha; Wed, 02 Nov 2022 00:11:33 +0000
Received: by outflank-mailman (input) for mailman id 435328;
 Wed, 02 Nov 2022 00:11:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lw-0001C5-Dq
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lw-00037o-D7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Lw-0007Zf-C6
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=6LhAdTyuH5wUF5wq7d3FBegTmqpAnnQFafLjFULMc7s=; b=2UwoM7aA+0QkP1p4liLBJ4BXoi
	JVLPMTR8mr81Gr0iYZGUQrm3+a/IjngLa4YejFAo8eAD8CT4hYhtEGQumEG6EMCtt6TV0I4FKIEfs
	P0KjfhmpccTy+1fF2Joq2Ave0NHyy1eoCW00KB6zOmWyIco00mVZLSqDwqzp4QvAD2YM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: split up send_reply()
Message-Id: <E1oq1Lw-0007Zf-C6@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:11:32 +0000

commit ce6aea73f6c4c90fab2500933b3a488e2f30334b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32)
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 39 ++++-----------------
 3 files changed, 52 insertions(+), 62 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e9c9695fd1..249ad5ec6f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -767,49 +767,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -817,8 +800,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 0004fa848c..9af9af4390 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -187,6 +187,7 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index aca0a71bad..99a2c266b2 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -85,35 +85,6 @@ static const char *get_watch_path(const struct watch *watch, const char *name)
 	return path;
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
-{
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
-
-	name = get_watch_path(watch, name);
-
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
-}
-
 /*
  * Check permissions of a specific watch to fire:
  * Either the node itself or its parent have to be readable by the connection
@@ -190,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -292,7 +267,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:11:43 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:11:43 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435329.688451 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1M7-0001Es-Lt; Wed, 02 Nov 2022 00:11:43 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435329.688451; Wed, 02 Nov 2022 00:11:43 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1M7-0001El-JA; Wed, 02 Nov 2022 00:11:43 +0000
Received: by outflank-mailman (input) for mailman id 435329;
 Wed, 02 Nov 2022 00:11:42 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1M6-0001EZ-Gw
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1M6-00039o-GH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1M6-0007aA-FS
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=N/Q1GGowbwo6S6/At1+QiIiJc/O81Ktn8uDi3ZmBVbQ=; b=Imp+GoBZ/ZrNpYocdf5xZoQRNp
	k6t6MZ42Qy+WSZbV/ZgrvFt+YwbQyb6RtPkZKJrwRbXUAKRr1sW9tIdVUQ2a/ahtUa3ElClzfI6kS
	ZFyJcWaYlr3F/c6MINDZBKL6C6kwqEkDDClomwxIU/5iaaF+/Okt0F3SFC+slPQx7Xt8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1oq1M6-0007aA-FS@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:11:42 +0000

commit f8af1a27b00e373bfb5f5e61b14c51165a740fa4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ead062a68a9c201a95488e84750a70a107f7b317)
---
 tools/xenstore/xenstored_core.c   | 26 +++++++++++++++++---------
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c |  7 +------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 249ad5ec6f..527a1ebded 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -211,6 +211,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -254,8 +269,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
@@ -1506,18 +1520,12 @@ static struct {
  */
 void ignore_connection(struct connection *conn)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored\n", conn);
 
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 9af9af4390..e7ee87825c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -276,6 +276,8 @@ int remember_string(struct hashtable *hash, const char *str);
 
 void set_tdb_key(const char *name, TDB_DATA *key);
 
+void conn_free_buffered_data(struct connection *conn);
+
 const char *dump_state_global(FILE *fp);
 const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 				     struct xs_state_connection *sc);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index d03c7d93a9..93c4c1edcd 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -411,15 +411,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:11:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:11:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435330.688454 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1MH-0001Ha-NS; Wed, 02 Nov 2022 00:11:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435330.688454; Wed, 02 Nov 2022 00:11:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1MH-0001HT-Kp; Wed, 02 Nov 2022 00:11:53 +0000
Received: by outflank-mailman (input) for mailman id 435330;
 Wed, 02 Nov 2022 00:11:52 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1MG-0001HC-Jq
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:52 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1MG-00039y-JC
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:52 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1MG-0007aa-IV
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:11:52 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=FOmZ6ZDWbmaIO4Gh+lNBTwajgvlXExmNASBRdF+0/6A=; b=1o7zSXvSwsND1uwyOTGsD0/cdd
	1/yoYAYUsPfnKUaD6h9Xhuozq8hi5Ipj6Ca6OysPXm8uqnqnW6k5nsmVUByoYKezU5Gf68lwecIq+
	MFo0mG5Au/dIBKi7cAi4y23VnnFvBxTFd97JeWaIWLAQKJWc3DEUn/YxVt740VDqDP6w=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: reduce number of watch events
Message-Id: <E1oq1MG-0007aa-IV@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:11:52 +0000

commit e26d6f4d1b389b859fb5a6570421e80e0213f92b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297)
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 527a1ebded..bf22438739 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1295,7 +1295,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1307,7 +1307,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1319,7 +1319,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1345,13 +1350,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index faf6c930e4..54432907fc 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -323,6 +327,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 99a2c266b2..205d9d8ea1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:12:03 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:12:03 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435331.688459 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1MR-0001Mk-Qy; Wed, 02 Nov 2022 00:12:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435331.688459; Wed, 02 Nov 2022 00:12:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1MR-0001Mc-Nr; Wed, 02 Nov 2022 00:12:03 +0000
Received: by outflank-mailman (input) for mailman id 435331;
 Wed, 02 Nov 2022 00:12:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1MQ-0001MH-NF
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1MQ-0003AL-MQ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1MQ-0007b8-Lf
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=hGwKYfwrTmEw0EMYkDdYX0OvVH4wZf0RaLZp2uNxR/E=; b=KrHY/TY16PLWAte16+RjO8ULgB
	27iuWi6QprzMGmTO+O2bxonrrjN6EdD0RwZz9CicK2sLOjRn6JmIaPAS2iOlzdAgX/f5dC/lR8fXu
	0U4HPCKoHpxv0XJYON5MdP4sAscra3z4gpPln3AXwu1s3HOcqy4ZMo4srdBbNbBZjrGc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: let unread watch events time out
Message-Id: <E1oq1MQ-0007b8-Lf@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:12:02 +0000

commit d08cdf0b19daf948a6b9754e90de9bc304bcd262
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 5285dcb1a5c01695c11e6397c95d906b5e765c98)
---
 tools/xenstore/xenstored_core.c | 133 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index bf22438739..45244c021c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -108,6 +108,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -211,19 +213,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -411,6 +486,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -431,10 +507,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (conn_can_read(conn) ||
 			    (conn_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -794,6 +872,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -845,6 +924,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -2201,6 +2286,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2223,6 +2311,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2236,6 +2325,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2250,7 +2372,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:U", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2300,6 +2422,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
@@ -2741,6 +2866,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 		barf("error restoring buffered data");
 
 	memcpy(bdata->buffer, data, len);
+	if (bdata->hdr.msg.type == XS_WATCH_EVENT && timeout_watch_event_msec &&
+	    domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index e7ee87825c..8a81fc693f 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -67,6 +68,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -118,6 +121,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -244,6 +248,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:12:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:12:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435332.688463 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Mb-0001Pq-SU; Wed, 02 Nov 2022 00:12:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435332.688463; Wed, 02 Nov 2022 00:12:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Mb-0001Pi-Pd; Wed, 02 Nov 2022 00:12:13 +0000
Received: by outflank-mailman (input) for mailman id 435332;
 Wed, 02 Nov 2022 00:12:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Ma-0001PV-QH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Ma-0003AV-Pe
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Ma-0007bX-Op
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=pbJC8nwJ7Ai4YMx06EM5NcOvK4Quf6vVtx/vvsxsRMg=; b=XAmxErtmYw47sN9R/gVeSiEp2R
	aoIzrL8LsBT1HWv1hNuzi09JRHTmD3t/QsSespyZl6mMkuxT3Zg1prMUTGZkuD3EcOogSN1XLxfxn
	Lmw19iRaKPyMrJNFfFdKvcWmY0JKBJocrVHfwuEWEIMA6az9QqFwU9hv1KhGRzC1RcAA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: limit outstanding requests
Message-Id: <E1oq1Ma-0007bX-Op@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:12:12 +0000

commit 49344fb86ff040bae1107e236592c2d4dc4607f3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 36de433a273f55d614c83b89c9a8972287a1e475)
---
 tools/xenstore/xenstored_core.c   | 88 +++++++++++++++++++++++++++++++++++++--
 tools/xenstore/xenstored_core.h   | 20 ++++++++-
 tools/xenstore/xenstored_domain.c | 38 ++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 +++++--
 5 files changed, 150 insertions(+), 14 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 45244c021c..488d540f3a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -107,6 +107,7 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -223,12 +224,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -244,6 +257,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -405,6 +442,7 @@ int delay_request(struct connection *conn, struct buffered_data *in,
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -418,6 +456,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -893,6 +936,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -900,7 +945,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -930,8 +976,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1740,6 +1791,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1808,6 +1860,7 @@ struct connection *new_connection(const struct interface_funcs *funcs)
 	new->is_stalled = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 	INIT_LIST_HEAD(&new->delayed);
@@ -2286,6 +2339,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2311,6 +2367,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2358,6 +2415,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2372,8 +2443,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
-				  NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
 			no_domain_init = true;
@@ -2422,6 +2493,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
@@ -2875,6 +2949,14 @@ static void add_buffered_data(struct buffered_data *bdata,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	/*
+	 * Watch events are never "outstanding", but the request causing them
+	 * are instead kept "outstanding" until all watch events caused by that
+	 * request have been delivered.
+	 */
+	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
+		domain_outstanding_inc(conn);
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 8a81fc693f..db09f463a6 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -56,6 +56,8 @@ struct xs_state_connection;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -63,6 +65,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -123,6 +136,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -191,7 +207,8 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -247,6 +264,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 93c4c1edcd..850085a92c 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -78,6 +78,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -183,8 +186,12 @@ static bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	return (intf->req_cons != intf->req_prod);
 }
@@ -331,7 +338,7 @@ static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -392,9 +399,6 @@ static int new_domain(struct domain *domain, int port, bool restore)
 	domain->conn->domain = domain;
 	domain->conn->id = domain->domid;
 
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
-
 	return 0;
 }
 
@@ -938,6 +942,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 1e929b8f8c..4f51b00529 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,6 +64,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 205d9d8ea1..0755ffa375 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -269,8 +272,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	trace_create(watch, "watch");
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:12:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:12:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435333.688467 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ml-0001Si-U2; Wed, 02 Nov 2022 00:12:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435333.688467; Wed, 02 Nov 2022 00:12:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ml-0001Sb-RM; Wed, 02 Nov 2022 00:12:23 +0000
Received: by outflank-mailman (input) for mailman id 435333;
 Wed, 02 Nov 2022 00:12:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Mk-0001SP-TQ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Mk-0003Ai-Sq
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Mk-0007c6-Ry
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=zNv8Z8uYy0hhJ7dxGUCUQtqeymot/ll+Rivfp5oDWak=; b=madrbsd7xvX4G2pdarI2eNFvp3
	KsZ3E7hBi9nxFus777Z3c+3+V+2cKZl74yvGHPdqzvcjN0pFMhrmabvpb6LxAzZ8s5a1Jkm7kskP3
	7WmT2TyeJu0oC1fgcxCGxpxdh1/WZzQUUJ2tn+kMQMIYcDsuyUQTLD1Y+x1amp6rdJ/U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1oq1Mk-0007c6-Ry@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:12:22 +0000

commit b270ad4a7ebe3409337bf3730317af6977c38197
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2)
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 488d540f3a..f1fa97b8cf 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -916,6 +916,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -948,7 +949,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -970,12 +971,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index db09f463a6..b9b50e81c7 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -62,6 +62,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:12:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:12:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435334.688470 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Mw-0001WB-0s; Wed, 02 Nov 2022 00:12:34 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435334.688470; Wed, 02 Nov 2022 00:12:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Mv-0001W4-US; Wed, 02 Nov 2022 00:12:33 +0000
Received: by outflank-mailman (input) for mailman id 435334;
 Wed, 02 Nov 2022 00:12:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Mv-0001Vs-0J
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Mu-0003Ar-Vu
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Mu-0007cd-V6
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NOwpW2QED9vwHBrcauqr4Xj8Zmhs7+TEsoaTMEqPD50=; b=ek+8Pq4t833suyMnOViUajQIFB
	DcxfiwCOOsRo2rckj96ymFYDForvyEOJHU5+e76T6jqjQsf9aZvcmLjYaAL5uO2q8+JeCH2DOYM4E
	gM/Lw///4AzleeNcvkICiccpZLC51vWvNNunrdQOWoYQtXn4CnkLjKHH2RodhGm6e8qM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: fix connection->id usage
Message-Id: <E1oq1Mu-0007cd-V6@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:12:32 +0000

commit 787241f55216d34ca025c835c6a2096d7664d711
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831)
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 7b4300ef77..adb8d51b04 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -891,7 +891,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	unsigned int cmd, num, off;
 	char **vec = NULL;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	off = get_string(in, 0);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index b9b50e81c7..b1a70488b9 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -123,7 +123,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this connection ignored? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 54432907fc..ee1b09031a 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -477,7 +477,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:12:44 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:12:44 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435335.688475 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1N6-0001Yt-2H; Wed, 02 Nov 2022 00:12:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435335.688475; Wed, 02 Nov 2022 00:12:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1N5-0001Yl-Vl; Wed, 02 Nov 2022 00:12:43 +0000
Received: by outflank-mailman (input) for mailman id 435335;
 Wed, 02 Nov 2022 00:12:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1N5-0001YS-3U
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1N5-0003BB-2h
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1N5-0007dN-23
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9NfBb+Lxm9JmJ1xv6Tz8S6/AThdNqkBAAWg+FVF7Wlk=; b=J1Tc23ea9B6YQDaWRYJuqB/sBy
	rkAN5n48yHK/Nv9FUu8xX2pMo70bbbKjEb9DZjdQsJlC1VI8gY8UTXpAdD7SMc5cKTWDXmsSvHzYb
	QZPw9xIJb5nxWO49weOzmM2tPUJ3UHHYf3GMf4mAVI67Ir4T9mgVfQ2ECkm5DY6TA5To=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1oq1N5-0007dN-23@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:12:43 +0000

commit 717460e062dfe13a69cb01f518dd7b65d39376ef
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit dbef1f7482894c572d90cd73d99ed689c891e863)
---
 tools/xenstore/xenstored_core.c        |  43 +++++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 4 files changed, 109 insertions(+), 51 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f1fa97b8cf..692d863fce 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -638,7 +638,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -660,7 +660,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1272,13 +1272,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1328,8 +1332,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1614,10 +1622,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
+
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
 
-	if (write_node(conn, node, false))
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
@@ -3122,7 +3147,9 @@ void read_state_node(const void *ctx, const void *state)
 	set_tdb_key(name, &key);
 	if (write_node_raw(NULL, &key, node, true))
 		barf("write node error restoring node");
-	domain_entry_inc(&conn, node);
+
+	if (domain_entry_inc(&conn, node))
+		barf("node accounting error restoring node");
 
 	talloc_free(node);
 }
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 850085a92c..260952e090 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -363,6 +364,18 @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid)
 	return domain ? : alloc_domain(ctx, domid);
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port, bool restore)
 {
 	int rc;
@@ -782,30 +795,28 @@ void domain_deinit(void)
 		xenevtchn_unbind(xce_handle, virq_port);
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -841,7 +852,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -851,8 +862,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -871,25 +888,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -899,13 +916,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4f51b00529..d6519904d8 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -54,10 +54,10 @@ const char *get_implicit_path(const struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ee1b09031a..86caf6c398 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -519,8 +519,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:12:54 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:12:54 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435336.688479 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1NG-0001bY-3r; Wed, 02 Nov 2022 00:12:54 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435336.688479; Wed, 02 Nov 2022 00:12:54 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1NG-0001bQ-15; Wed, 02 Nov 2022 00:12:54 +0000
Received: by outflank-mailman (input) for mailman id 435336;
 Wed, 02 Nov 2022 00:12:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NF-0001bI-6J
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NF-0003BF-5h
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NF-0007dm-4y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:12:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ffcvsAuBVFdQtgyLKr18SXU+j1DJFuBinpdZX372vvU=; b=sd/zmw97QX3yD9AUHW446vtjXZ
	I7EwhNTRkjTfNxV4i9xXx0QpOQ6yuNMTVbsJVb06kFoV1cHMma1OzVAGWjU9tc/9matVEAwbFl9EV
	juTmavpJEK2jP94yzBAHiiahu3AR0P2p5ywL68GwMWIek9MgT50TIGc0Sb/uh0K3Xe7Q=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1oq1NF-0007dm-4y@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:12:53 +0000

commit 7017cfefc455db535054ebc09124af8101746a4a
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 268369d8e322d227a74a899009c5748d7b0ea142)
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  1 +
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index a16e0c3807..bafc90e2f6 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -63,4 +63,8 @@
 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 692d863fce..f835aa1b2f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -106,6 +106,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
 
@@ -595,6 +596,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -616,14 +618,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -638,19 +639,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -767,7 +785,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -829,7 +847,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1235,7 +1253,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1509,7 +1527,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1539,7 +1557,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2384,6 +2402,8 @@ static void usage(void)
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2468,6 +2488,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index b1a70488b9..245f925823 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -268,6 +268,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 86caf6c398..7bd41eb475 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -260,6 +263,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -297,6 +305,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:13:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:13:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435338.688483 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1NQ-0001ex-5I; Wed, 02 Nov 2022 00:13:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435338.688483; Wed, 02 Nov 2022 00:13:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1NQ-0001ep-2j; Wed, 02 Nov 2022 00:13:04 +0000
Received: by outflank-mailman (input) for mailman id 435338;
 Wed, 02 Nov 2022 00:13:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NP-0001ed-9a
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NP-0003Bd-8s
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NP-0007ee-81
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=d0ANQ4rSnsCRJt5gWX+lkeyQM052sjrwmENIABAcM34=; b=j4+DvOYd6WVSyWYWhnwFgewXcY
	B5uXDvXGg/RPDiXWBX5yA/Q1dWidem0tEBNMGhA214AWJQRFicAGZvX5umpRxxhFvryxPPxxcVOwM
	vhKq8dAag0IM3r3gLjZtHGwfvW0kxcKOdrbXLNGYq5YXA5Gob/+7rQQfOtG+czmwin+I=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1oq1NP-0007ee-81@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:13:03 +0000

commit 2d39cf77d70b44b70f970da90187f48d2c0b3e96
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 60e2f6020dea7f616857b8fc1141b1c085d88761)
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 3 +++
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f835aa1b2f..5171d34c94 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2039,7 +2039,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -2078,7 +2079,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(bool live_update)
+void setup_structure(bool live_update)
 {
 	char *tdbname;
 
@@ -2101,6 +2102,7 @@ static void setup_structure(bool live_update)
 		manual_node("/", "tool");
 		manual_node("/tool", "xenstored");
 		manual_node("/tool/xenstored", NULL);
+		domain_entry_fix(dom0_domid, 3, true);
 	}
 
 	check_store();
@@ -2614,9 +2616,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure(live_update);
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init && !live_update) {
 		domain_init(-1);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 245f925823..2c77ec7ee0 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -231,6 +231,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(bool live_update);
 struct connection *new_connection(const struct interface_funcs *funcs);
 struct connection *get_connection_by_id(unsigned int conn_id);
 void ignore_connection(struct connection *conn);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 260952e090..f04b7aae8a 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -470,6 +470,9 @@ static struct domain *introduce_domain(const void *ctx,
 		}
 		domain->interface = interface;
 
+		if (is_master_domain)
+			setup_structure(restore);
+
 		/* Now domain belongs to its connection. */
 		talloc_steal(domain->conn, domain);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:13:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:13:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435339.688487 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Na-0001iK-8f; Wed, 02 Nov 2022 00:13:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435339.688487; Wed, 02 Nov 2022 00:13:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Na-0001iC-5d; Wed, 02 Nov 2022 00:13:14 +0000
Received: by outflank-mailman (input) for mailman id 435339;
 Wed, 02 Nov 2022 00:13:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NZ-0001hv-Ce
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NZ-0003Bh-C3
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1NZ-0007f5-BN
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=IoG3kWuBTMTmcaagXdJWFeDrkdeMgiOcXK41LguX0pE=; b=G4ifI/q+Kk6XemJ2RUKbUjaxgI
	X7Xyjhq02RZjke/VuiNfiBJHbZsJTiSU3PJEwx6W9ZCkYTP8Hns9iOom4L7iZ+OGpnZqFauBq9tMI
	SixrwDbABApzHf14nrEYyU8DbtScG67/tVusy7O2U2Lx5atKvf36D229MgeigDGo/pd8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1oq1NZ-0007f5-BN@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:13:13 +0000

commit 2e406cf5fbb817341dc860473158382057e13de5
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d4a8ec7a93faedbe54fd197db146de628459e77)
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5171d34c94..b2bf6740d4 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -109,6 +109,8 @@ int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2406,7 +2408,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2433,6 +2442,7 @@ static struct option options[] = {
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2480,7 +2490,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2488,11 +2498,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2510,7 +2525,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2561,7 +2576,10 @@ int main(int argc, char *argv[])
 						 quota_max_path_len);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2c77ec7ee0..373af18297 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -270,6 +270,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index f04b7aae8a..94fd561e9d 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -76,6 +76,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -192,6 +199,9 @@ static bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	return (intf->req_cons != intf->req_prod);
@@ -950,6 +960,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index d6519904d8..633c9a0a0a 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -61,6 +61,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:13:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:13:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435340.688490 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Nk-0001l0-9y; Wed, 02 Nov 2022 00:13:24 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435340.688490; Wed, 02 Nov 2022 00:13:24 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Nk-0001ks-7E; Wed, 02 Nov 2022 00:13:24 +0000
Received: by outflank-mailman (input) for mailman id 435340;
 Wed, 02 Nov 2022 00:13:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Nj-0001kj-Fh
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:23 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Nj-0003Bs-F2
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:23 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Nj-0007fU-EJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:23 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Vh+X6P9Rjo3itm0NESav4rXOACTygaei8CBaGylssEo=; b=Nelbc3myffNvyrsNaY6y3brcAi
	xWoCelv+pLIeXZiYOcnVArzMIWjT23ibgcqtwzqi1L8zYPUwG80w+mCxw7qEBhkJMpEa1EhRVNisV
	y1E276M3imc3GPnLGTPJjh4JWS0pAWJeiIHpe3KZWNhpZXubQTMs86eq1JMVfkfpvWJY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: add memory accounting for responses
Message-Id: <E1oq1Nj-0007fU-EJ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:13:23 +0000

commit 30c8e752f66f681b5c731a637c26510ae5f35965
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    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 f6d00133643a524d2138c9e3f192bbde719050ba)
---
 tools/xenstore/xenstored_core.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b2bf6740d4..ecab6cfbbe 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -260,6 +260,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -938,11 +940,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -1007,6 +1012,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
@@ -3039,6 +3049,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 	 */
 	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
 		domain_outstanding_inc(conn);
+	/*
+	 * We are restoring the state after Live-Update and the new quota may
+	 * be smaller. So ignore it. The limit will be applied for any resource
+	 * after the state has been fully restored.
+	 */
+	domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:13:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:13:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435341.688495 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Nv-0001nx-BY; Wed, 02 Nov 2022 00:13:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435341.688495; Wed, 02 Nov 2022 00:13:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Nv-0001np-8l; Wed, 02 Nov 2022 00:13:35 +0000
Received: by outflank-mailman (input) for mailman id 435341;
 Wed, 02 Nov 2022 00:13:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Nt-0001nd-Lt
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Nt-0003C2-ID
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:33 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Nt-0007fv-HP
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:33 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=tLc2eCoJDLwigz3RGiA8vLgswmFzKkgjCb9p1DYMqJc=; b=gC8FMmo8AXzJrrE0y0c919vY+W
	qjPI7al2MfqqgHTXIMWoR4nTenuCFKaImFL4oDbSpA/ZwEiUNVrH5lLBoMkLxdfXl/qNmbbhd4pAG
	S0IGK5cyDzrt7ILgddnxTPDc5mS2pkQIeuSFEmfp+0X92kPtrzJG1uhfouvW09Ja0OIE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: add memory accounting for watches
Message-Id: <E1oq1Nt-0007fv-HP@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:13:33 +0000

commit bce985745cde48a339954759677b77d3eeec41f3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    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 7f9978a2cc37aaffab2fb09593bc598c0712a69b)
---
 tools/xenstore/xenstored_core.c  |  1 +
 tools/xenstore/xenstored_watch.c | 13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ecab6cfbbe..d86942f5aa 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -463,6 +463,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 0755ffa375..fdf9b2d653 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -211,7 +211,7 @@ static int check_watch_path(struct connection *conn, const void *ctx,
 }
 
 static struct watch *add_watch(struct connection *conn, char *path, char *token,
-			       bool relative)
+			       bool relative, bool no_quota_check)
 {
 	struct watch *watch;
 
@@ -222,6 +222,9 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	watch->token = talloc_strdup(watch, token);
 	if (!watch->node || !watch->token)
 		goto nomem;
+	if (domain_memory_add(conn->id, strlen(path) + strlen(token),
+			      no_quota_check))
+		goto nomem;
 
 	if (relative)
 		watch->relative_path = get_implicit_path(conn);
@@ -265,7 +268,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (domain_watch(conn) > quota_nb_watch_per_domain)
 		return E2BIG;
 
-	watch = add_watch(conn, vec[0], vec[1], relative);
+	watch = add_watch(conn, vec[0], vec[1], relative, false);
 	if (!watch)
 		return errno;
 
@@ -296,6 +299,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -311,6 +316,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
@@ -373,7 +380,7 @@ void read_state_watch(const void *ctx, const void *state)
 	if (!path)
 		barf("allocation error for read watch");
 
-	if (!add_watch(conn, path, token, relative))
+	if (!add_watch(conn, path, token, relative, true))
 		barf("error adding watch");
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:13:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:13:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435342.688499 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1O5-0001qg-Dr; Wed, 02 Nov 2022 00:13:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435342.688499; Wed, 02 Nov 2022 00:13:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1O5-0001qY-AT; Wed, 02 Nov 2022 00:13:45 +0000
Received: by outflank-mailman (input) for mailman id 435342;
 Wed, 02 Nov 2022 00:13:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1O3-0001qI-Lz
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1O3-0003CX-LG
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1O3-0007gM-Kd
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=VylbdDMSnll7VoinAm1UqrZyEW2+mSpHol20ZQsU4sY=; b=IatoxBkZJxjpKARxWEbr32FhYP
	RHIenhj+jg+v1SGxzvETnwPmn1dwskxtM/Xcqn7+n2uUtKUqllik6VtOJFnFYl9rNSn1/AgIDYFx5
	hnL23sZNYOefuU7m3vWrClVIL4t0HUztmbou/CBSxT4e5538UVtKpvurJHzOr2Vx2Qi8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: add memory accounting for nodes
Message-Id: <E1oq1O3-0007gM-Kd@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:13:43 +0000

commit 578d422af0b444a9e437dd0ceddf2049364f1a40
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    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 d86942f5aa..16504de420 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -591,6 +591,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.
@@ -644,9 +755,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. */
@@ -715,12 +832,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;
 }
 
@@ -1222,7 +1336,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;
 	}
@@ -1295,6 +1409,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;
 
@@ -1303,17 +1418,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);
 
 	/*
@@ -1365,7 +1480,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;
 			}
 		}
@@ -2291,7 +2406,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);
 		}
 	}
 
@@ -3149,6 +3264,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 373af18297..da9ecce67f 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -176,6 +176,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 */
@@ -198,6 +203,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. */
@@ -306,6 +314,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 7bd41eb475..ace9a11d77 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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:13:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:13:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435343.688503 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1OF-0001uB-GX; Wed, 02 Nov 2022 00:13:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435343.688503; Wed, 02 Nov 2022 00:13:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1OF-0001u3-Dl; Wed, 02 Nov 2022 00:13:55 +0000
Received: by outflank-mailman (input) for mailman id 435343;
 Wed, 02 Nov 2022 00:13:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1OD-0001tr-Ok
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1OD-0003Ch-O9
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1OD-0007iI-NY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:13:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=CRn9+BiG5+fsE4OQSr/9uJIpsemdO1pfMiCAd1Eh8TI=; b=tHuSJzmwJUt0EHmM3jK+FRO4zw
	TVH71h2i6Gp5kOS9vewPGWDHDrr8HfL/dO5nQ2kkaqCpoXNtY9QPyn7nkvXQQG9DLi6xyIMruq5I0
	w+v2otFr2pyeXnSYEXSajDdpzD4iRP1Y370yUvmBZnlLXJYCJePBxOlepoNghiO4ikqw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: add exports for quota variables
Message-Id: <E1oq1OD-0007iI-NY@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:13:53 +0000

commit 0a67b4eef104c36bef52990e413ef361acc8183c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 1da16d5990b5f7752657fca3e948f735177ea9ad)
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index da9ecce67f..bfd3fc1e9d 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -275,6 +275,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ace9a11d77..28774813de 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static struct accessed_node *find_accessed_node(struct transaction *trans,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index fdf9b2d653..85362bcce3 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:14:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:14:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435344.688507 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1OP-0001ww-I7; Wed, 02 Nov 2022 00:14:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435344.688507; Wed, 02 Nov 2022 00:14:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1OP-0001wo-FL; Wed, 02 Nov 2022 00:14:05 +0000
Received: by outflank-mailman (input) for mailman id 435344;
 Wed, 02 Nov 2022 00:14:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1ON-0001wV-Rj
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1ON-0003D6-R5
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1ON-0007iu-QN
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0/EDoSD5vMmGzgaZrXHLvyPE68+HlKg5s3OzBecBtCc=; b=DpC5AZhvaitGkRK3e+rY8y6vHy
	AM1qt454jbi0aifpCiAUIE1MEyMPi6Ww0G4vPdvV2RZJLZNt3989lQvDLy2XLdrnHloehIyVLioWd
	3B8USIkRLdQCeikdiY419sUUQ0PIGXCru6lH7CXkPsBruY6WkE3MOPDPEnpxQHRuf83w=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1oq1ON-0007iu-QN@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:14:03 +0000

commit b584b9b95687655f4f9f5c37fea3b1eea3f32886
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 334dc8b6fd..a7d006519a 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -366,6 +366,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index adb8d51b04..1031a81c38 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -196,6 +196,115 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "path-max", &quota_max_path_len, "Max. length of a node path" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 #ifdef __MINIOS__
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
@@ -847,6 +956,8 @@ static struct cmd_s cmds[] = {
 	{ "memreport", do_control_memreport, "[<file>]" },
 #endif
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 94fd561e9d..e7c6886ccf 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -345,6 +346,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 633c9a0a0a..904faa923a 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -87,6 +87,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:14:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:14:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435345.688513 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1OZ-0001zt-Km; Wed, 02 Nov 2022 00:14:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435345.688513; Wed, 02 Nov 2022 00:14:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1OZ-0001zj-Gq; Wed, 02 Nov 2022 00:14:15 +0000
Received: by outflank-mailman (input) for mailman id 435345;
 Wed, 02 Nov 2022 00:14:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1OX-0001zU-UZ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1OX-0003DA-Tx
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1OX-0007jW-TI
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NkTGhnH2n5vEVJk2sdfA/9xNvV97X01VLKoNCv+dXEY=; b=mzO9dCxdGBw2fjvg1tJJmurWNn
	eoq+SiLOxcuY+992tYS7XRHoR+gUn26GsEGSNaovhQZ5XMa5A+dJa+kbspGOQZ6kSss4jwquokwrQ
	i6WVMbGWejq0jv7zbF/RM5sloMwtTChN7kjklC15EXD6SNd4Rzqc1lpOs8AVtqiG8JKQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1oq1OX-0007jW-TI@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:14:13 +0000

commit b0e95b451225de4db99bbe0b8dc79fdf08873e9e
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 84734955d4bf629ba459a74773afcde50a52236f)
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ebe18b8e31..6b06f80859 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -21,9 +21,9 @@ let xs_daemon_socket = Paths.xen_run_stored ^ "/socket"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:14:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:14:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435346.688515 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Oj-00022W-L3; Wed, 02 Nov 2022 00:14:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435346.688515; Wed, 02 Nov 2022 00:14:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Oj-00022O-IN; Wed, 02 Nov 2022 00:14:25 +0000
Received: by outflank-mailman (input) for mailman id 435346;
 Wed, 02 Nov 2022 00:14:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Oi-00022G-1G
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Oi-0003DF-0b
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Oh-0007k3-WA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:23 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sZ1DqUWAMCwKCmAgRpTlcStSsEc5x6dYHPa9dPlf2Vc=; b=0KiFwA7lF3gAa7ik7tpKVQaQvG
	/+uudT7qZSVIVz4THr0yw9iGp0v4GGp5Gs0LuzozfApadwS9UxZXhJHlmds27zAcmAtO7Jds8/QS5
	8y7leLOt+nvhshtNr2Y1ogZ4U/EWoI2/X24JTFSTMULDyZK2/g5c86Ldtad56dZIEivI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1oq1Oh-0007k3-WA@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:14:23 +0000

commit ab21bb1971a7fa9308053b0686f43277f6e8a6c9
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    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 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff)
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 27790d4a5c..dd58e6979c 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -389,6 +389,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"
@@ -681,9 +682,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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:14:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:14:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435347.688519 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ot-000258-Nh; Wed, 02 Nov 2022 00:14:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435347.688519; Wed, 02 Nov 2022 00:14:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ot-000250-Jv; Wed, 02 Nov 2022 00:14:35 +0000
Received: by outflank-mailman (input) for mailman id 435347;
 Wed, 02 Nov 2022 00:14:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Os-00024b-42
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Os-0003DJ-3M
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Os-0007ka-2l
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=yRDxTAISMgmY242wm0owlqVoOX/UmATLThHfUJMfKRQ=; b=pg6KvbjwE51wjx9XKAndGn0d1U
	LpnmSnVz/ByR5Eq+EcFHvLQvhcXsJAj6su1dX8z91mITKB4o38Ryx31odKNX2YhS/XBwIn7hWUgZE
	uMZMvkQpC2jmxpsWEeDi8SCW/5Bqx9fVqLB8ZJA92I/jCAflbi7wcW0Xds6WS+y4/ey4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml: GC parameter tuning
Message-Id: <E1oq1Os-0007ka-2l@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:14:34 +0000

commit a63bbcf5318b487ca86574d7fcf916958af5ed02
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 4a8bacff20b857ca0d628ef5525877ade11f2a42)
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 6b06f80859..ba63a8147e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index d44ae673c4..3b57ad016d 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -104,6 +104,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -265,6 +266,67 @@ let to_file store cons fds file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -274,6 +336,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:14:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:14:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435348.688523 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1P3-00028Q-PT; Wed, 02 Nov 2022 00:14:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435348.688523; Wed, 02 Nov 2022 00:14:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1P3-00028I-Mu; Wed, 02 Nov 2022 00:14:45 +0000
Received: by outflank-mailman (input) for mailman id 435348;
 Wed, 02 Nov 2022 00:14:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1P2-000280-6u
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1P2-0003Dd-6H
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1P2-0007kz-5g
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=fHNBEPBPZUjKZuU7FyVqROCx4YBUP4jbNiCv7XBDi6Q=; b=ZwAgGy5ykCouncfMAIncFGfYk5
	4pRc7A4k9f4sCCULdq9YwLXe2yZWAetRkxWp1/myANdGSELKxMneS7WZptuTlNzuFuixQTqREvaX5
	XwQg1mQbdP2lYaKi+uQaoR+UfRAvhphK7KojCC3ENxntaHc8CIyPFxeDoRCXgzUKLT7M=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml/libs/xb: hide type of Xb.t
Message-Id: <E1oq1P2-0007kz-5g@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:14:44 +0000

commit 8b60ad49b46f2e020e0f0847df80c768d669cdb2
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Fri Jul 29 18:53:29 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml/libs/xb: hide type of Xb.t
    
    Hiding the type will make it easier to change the implementation
    in the future without breaking code that relies on it.
    
    No functional change.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba)
---
 tools/ocaml/libs/xb/xb.ml           | 3 +++
 tools/ocaml/libs/xb/xb.mli          | 9 ++-------
 tools/ocaml/xenstored/connection.ml | 8 ++------
 3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 104d319d77..8404ddd8a6 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out
 let input_len con = Queue.length con.pkt_in
 let has_in_packet con = Queue.length con.pkt_in > 0
 let get_in_packet con = Queue.pop con.pkt_in
+let has_partial_input con = match con.partial_in with
+	| HaveHdr _ -> true
+	| NoHdr (n, _) -> n < Partial.header_size ()
 let has_more_input con =
 	match con.backend with
 	| Fd _         -> false
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 3a00da6cdd..794e35bb34 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,13 +66,7 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
-type t = {
-  backend : backend;
-  pkt_in : Packet.t Queue.t;
-  pkt_out : Packet.t Queue.t;
-  mutable partial_in : partial_buf;
-  mutable partial_out : string;
-}
+type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
 val queue : t -> Packet.t -> unit
@@ -97,6 +91,7 @@ val has_output : t -> bool
 val peek_output : t -> Packet.t
 val input_len : t -> int
 val has_in_packet : t -> bool
+val has_partial_input : t -> bool
 val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 65f99ea6f2..38b47363a1 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -125,9 +125,7 @@ let get_perm con =
 let set_target con target_domid =
 	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
 
-let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with
-	| Xenbus.Xb.Xenmmap _ -> true
-	| _ -> false
+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
 let send_reply con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
@@ -280,9 +278,7 @@ let get_transaction con tid =
 
 let do_input con = Xenbus.Xb.input con.xb
 let has_input con = Xenbus.Xb.has_in_packet con.xb
-let has_partial_input con = match con.xb.Xenbus.Xb.partial_in with
-	| HaveHdr _ -> true
-	| NoHdr (n, _) -> n < Xenbus.Partial.header_size ()
+let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:14:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:14:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435349.688527 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1PD-0002BP-RF; Wed, 02 Nov 2022 00:14:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435349.688527; Wed, 02 Nov 2022 00:14:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1PD-0002BH-OO; Wed, 02 Nov 2022 00:14:55 +0000
Received: by outflank-mailman (input) for mailman id 435349;
 Wed, 02 Nov 2022 00:14:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PC-0002B0-9z
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PC-0003Dh-9I
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PC-0007lO-8c
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:14:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0ivQTBCVzkou9O0MVSp/c+ju4SeWeqSLVpalv4VGOEI=; b=Be4va6up8ej26VxeN2+FHoy89P
	Htqp9C9uyBswBhoIrffPnRTD3CVsB4akZcIHvwwqsOCSzXyoJ3F7Mf3ZT+GBogo4rfGWQgxh1k+DZ
	S5LaVd28W2HqvYP0Bc05R0g9fGlPma+siiYuQ6gigfo0v3k1QUJjqByLpgcptRkipsiA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1oq1PC-0007lO-8c@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:14:54 +0000

commit 59981b08c8ef6eed37b1171656c2a5f3b4b74012
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c0a86a462721008eca5ff733660de094d3c34bc7)
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  4 +---
 tools/ocaml/xenstored/process.ml    | 15 +++++++--------
 5 files changed, 20 insertions(+), 42 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 38b47363a1..cc20e047d2 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,9 +277,7 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
@@ -307,7 +305,7 @@ let is_bad con = match con.dom with None -> false | Some dom -> Domain.is_bad_do
    Restrictions below can be relaxed once xenstored learns to dump more
    of its live state in a safe way *)
 let has_extra_connection_data con =
-	let has_in = has_input con || has_partial_input con in
+	let has_in = has_partial_input con in
 	let has_out = has_output con in
 	let has_socket = con.dom = None in
 	let has_nondefault_perms = make_perm con.dom <> con.perm in
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index dd58e6979c..cbf7082137 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -195,10 +195,9 @@ let parse_live_update args =
 			| _ when Unix.gettimeofday () < t.deadline -> false
 			| l ->
 				warn "timeout reached: have to wait, migrate or shutdown %d domains:" (List.length l);
-				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, in: %b, out: %b, perm: %s"
+				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, out: %b, perm: %s"
 					(Connection.get_domstr con)
 					(Connection.number_of_transactions con)
-					(Connection.has_input con)
 					(Connection.has_output con)
 					(Connection.get_perm con |> Perms.Connection.to_string)
 					) l in
@@ -706,16 +705,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -725,8 +725,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:15:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:15:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435350.688530 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1PN-0002FO-Sk; Wed, 02 Nov 2022 00:15:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435350.688530; Wed, 02 Nov 2022 00:15:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1PN-0002FG-Q0; Wed, 02 Nov 2022 00:15:05 +0000
Received: by outflank-mailman (input) for mailman id 435350;
 Wed, 02 Nov 2022 00:15:04 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PM-0002EA-Cj
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:04 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PM-0003EE-C2
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PM-0007m7-BS
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=BJ22/Q91Fa4J1WWFnfYWLsk+3k8zyOutIcc6sTq/f9c=; b=dfZtEODT1iGBPK3xJiUt35j+RJ
	+CsBYidKGbxGgihMp2Qq9OXYEh3Js3cDqk5QGgBhSEUwMM9xJ+4gc4wyTOEdwqSCIz4l/69xSLgKa
	A4+TDagxCkksHH0dfcEP1DNTXB6z+rQrpfNegIo6H+jjP6mrB1G2TmPzctmoNPHYRVIQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1oq1PM-0007m7-BS@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:15:04 +0000

commit ea1567893b05df03fe65657f0a25211a6a9ff7ec
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 19171fb5d888b4467a7073e8febc5e05540956e9)
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:15:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:15:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435351.688535 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1PX-0002I6-Uu; Wed, 02 Nov 2022 00:15:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435351.688535; Wed, 02 Nov 2022 00:15:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1PX-0002Hy-Rf; Wed, 02 Nov 2022 00:15:15 +0000
Received: by outflank-mailman (input) for mailman id 435351;
 Wed, 02 Nov 2022 00:15:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PW-0002Hn-GI
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:14 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PW-0003EJ-Fe
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:14 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1PW-0007mk-EV
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:14 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=MczCciZRHhhIq41EZIEBIFEU4kNQ1vyMG7Ebji5i1LU=; b=kp2eo1pYG9lEBqs/D4mJ6RwMiZ
	HIfGdmBPRUxUzgRatxo6vpMOdDvpUvCSa3ur/w2f4PvFsdjpOUcgf0JU68hZillk6vYPNH0Zf178k
	Tei+i8iAYxdaujc746VzApVs6C5wU6uz5pfgdwIOhY0TGHso0LnPUKmYo75GPTDP2xtk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1oq1PW-0007mk-EV@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:15:14 +0000

commit cec3c52c287f5aee7de061b40765aca5301cf9ca
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96)
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index cc20e047d2..9624a5f9da 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -280,6 +408,7 @@ let do_input con = Xenbus.Xb.input con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -323,7 +452,7 @@ let prevents_live_update con = not (is_bad con)
 	&& (has_extra_connection_data con || has_transaction_data con)
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 3c7429fe7f..7d68c583b4 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: Connection.watch list Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -197,6 +216,16 @@ let debug cons =
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
 
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
+
 let filter ~f cons =
 	let fold _ v acc = if f v then v :: acc else acc in
 	[]
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ba63a8147e..327b6d795e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -24,6 +24,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index cbf7082137..ce39ce28b5 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -57,7 +57,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -67,8 +67,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -234,6 +235,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -342,7 +357,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -501,7 +516,7 @@ let do_watch con t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -532,7 +547,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -700,7 +715,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -728,6 +744,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 3b57ad016d..c799e20f11 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:15:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:15:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435352.688539 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ph-0002LK-2j; Wed, 02 Nov 2022 00:15:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435352.688539; Wed, 02 Nov 2022 00:15:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Pg-0002LA-W7; Wed, 02 Nov 2022 00:15:24 +0000
Received: by outflank-mailman (input) for mailman id 435352;
 Wed, 02 Nov 2022 00:15:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Pg-0002L4-JH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Pg-0003EN-Ib
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Pg-0007nB-Hv
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=D+qcmQF5g35XLK6nHYz+9DXYUhSoCw+ecq/bltTa8Wg=; b=T54mjcyeyUI9qsgvyD1MWY/3Wq
	TJal+EsNmr08Z/PybI2g+sGGEaLm2dleflyS+vgkq86wGKN+AAtRH3Ek0YOlTorjIJ7DU07uHU/ww
	4T36rL0tCpmYk3B9Zg8F1iYTGxZOoOOGjV0tLHmueU1FoKynLfzD4niTw2aZMRMSKJP0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1oq1Pg-0007nB-Hv@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:15:24 +0000

commit a026fddf89420dd25c5a9574d88aeab7c5711f6c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c7bc20d8d123851a468402bbfc9e3330efff21ec)
---
 SUPPORT.md | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index 85726102ea..7d0cb34c8f 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -179,13 +179,18 @@ Support for running qemu-xen device model in a linux stubdomain.
 
     Status: Tech Preview
 
-## Liveupdate of C xenstored daemon
+## Xenstore
 
-    Status: Tech Preview
+### C xenstored daemon
 
-## Liveupdate of OCaml xenstored daemon
+    Status: Supported
+    Status, Liveupdate: Tech Preview
 
-    Status: Tech Preview
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+    Status, Liveupdate: Not functional
 
 ## Toolstack/3rd party
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:15:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:15:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435353.688542 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Pr-0002OJ-48; Wed, 02 Nov 2022 00:15:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435353.688542; Wed, 02 Nov 2022 00:15:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Pr-0002OB-1Q; Wed, 02 Nov 2022 00:15:35 +0000
Received: by outflank-mailman (input) for mailman id 435353;
 Wed, 02 Nov 2022 00:15:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Pq-0002O4-MR
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Pq-0003ER-Lp
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Pq-0007nf-L5
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=HRFMcfYq3Kkx/ttIni/6JEN/kymxtTjmb2DhoObEGfY=; b=2cHrvL6rL3OxEJSa3hRZVQKtZi
	/N5nGT8zEl2VOibn3+MfwFmA5hxErobCovVZdiV8sMIZyCfqGGLILyhUAIsnvsMwzrw4Sl6R1uXMU
	ciHVvHep0wfpv7rYdCxnQcBsIs13lM59jSHt9qV4n0TK/esjUpRhmcRvbsBY1kQXloYg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1oq1Pq-0007nf-L5@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:15:34 +0000

commit c758765e464e166b5495c76466facc79584bbe1e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2a587de219cc0765330fbf9fac6827bfaf29e29b)
---
 tools/xenstore/xenstored_control.c     | 31 +++++++-------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 29 +++++++------
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 118 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 1031a81c38..d0350c6ad8 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -155,7 +155,7 @@ bool lu_is_pending(void)
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 	/*
 	 * max_pars can be used to limit the size of the parameter vector,
@@ -167,7 +167,7 @@ struct cmd_s {
 	unsigned int max_pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -179,7 +179,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -281,7 +281,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -293,7 +293,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -306,7 +306,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 }
 
 #ifdef __MINIOS__
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	if (num)
@@ -318,7 +318,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 #else
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -333,7 +333,7 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -373,7 +373,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -875,7 +875,7 @@ static const char *lu_start(const void *ctx, struct connection *conn,
 	return NULL;
 }
 
-static int do_control_lu(void *ctx, struct connection *conn,
+static int do_control_lu(const void *ctx, struct connection *conn,
 			 char **vec, int num)
 {
 	const char *ret = NULL;
@@ -922,7 +922,7 @@ static int do_control_lu(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -961,7 +961,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd, len = 0;
@@ -997,7 +997,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	unsigned int cmd, num, off;
 	char **vec = NULL;
@@ -1017,11 +1018,11 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (cmds[cmd].max_pars)
 		num = min(num, cmds[cmd].max_pars);
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) < num)
 		return EIO;
 
-	return cmds[cmd].func(in, conn, vec + 1, num - 1);
+	return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index 98b6fbcea2..a8cb76559b 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,7 +16,8 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 void lu_read_state(void);
 
 struct connection *lu_get_connection(void);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 16504de420..411cc0e447 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1248,11 +1248,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1261,7 +1263,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1273,7 +1275,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1300,7 +1303,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1316,11 +1319,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1510,7 +1515,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1524,12 +1530,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1540,18 +1546,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1561,10 +1568,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 			return errno;
 		if (!name)
 			return ENOMEM;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1662,24 +1669,25 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
 			if (!name)
 				return ENOMEM;
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1694,7 +1702,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1704,13 +1712,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1723,7 +1733,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1740,7 +1751,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1755,7 +1766,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1790,7 +1801,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1798,7 +1809,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1874,6 +1886,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	/* At least send_error() and send_reply() expects conn->in == in */
 	assert(conn->in == in);
@@ -1898,10 +1911,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index e7c6886ccf..fb732d0a14 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -330,7 +330,7 @@ bool domain_is_unprivileged(struct connection *conn)
 	       domid_is_unprivileged(conn->domain->domid);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -534,7 +534,8 @@ static struct domain *introduce_domain(const void *ctx,
 }
 
 /* domid, gfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -552,7 +553,7 @@ int do_introduce(struct connection *conn, struct buffered_data *in)
 	if (port <= 0)
 		return EINVAL;
 
-	domain = introduce_domain(in, domid, port, false);
+	domain = introduce_domain(ctx, domid, port, false);
 	if (!domain)
 		return errno;
 
@@ -575,7 +576,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -619,7 +621,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -634,7 +637,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -649,7 +653,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -657,18 +662,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -689,7 +693,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 904faa923a..b9e1528901 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -24,25 +24,32 @@ void handle_event(void);
 void check_domains(void);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(int evtfd);
 void dom0_init(void);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 28774813de..3e3eb47326 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -481,7 +481,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -494,8 +495,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -544,7 +545,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -562,8 +564,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	if (!conn->transaction_started)
 		conn->ta_start_time = 0;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 85362bcce3..316c08b7f7 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -243,7 +243,7 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	return NULL;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -252,7 +252,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	errno = check_watch_path(conn, in, &(vec[0]), &relative);
+	errno = check_watch_path(conn, ctx, &(vec[0]), &relative);
 	if (errno)
 		return errno;
 
@@ -283,7 +283,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -291,7 +292,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 0e693f0839..091890edca 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:15:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:15:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435354.688547 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Q1-0002RX-7N; Wed, 02 Nov 2022 00:15:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435354.688547; Wed, 02 Nov 2022 00:15:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Q1-0002RP-4d; Wed, 02 Nov 2022 00:15:45 +0000
Received: by outflank-mailman (input) for mailman id 435354;
 Wed, 02 Nov 2022 00:15:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Q0-0002RH-PZ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Q0-0003Eq-Ox
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Q0-0007o4-OI
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=195MSH3VcBcCTYMnZaFIZ2A9ubduoNIkf8g9kscZ4VY=; b=FSuXq7XK7rZ9arLj1VLQP3XV2E
	wX7ETVf9PpkRJp/WXfZ2P8wMjQ9RFWrHmrRmlUynYfVdl4hSDFdEEt2qGQE3MqmPPvfkgu+BDDYU1
	twoImT8ePV8pldl35PUQwPWQODy9sNtCsdVSP4XIqbl71D03gbXQArnz/GPiEjNVVe4Y=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: fix checking node permissions
Message-Id: <E1oq1Q0-0007o4-OI@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:15:44 +0000

commit 036fa8717b316a10b67ea8cf4d5dd200ac2b29af
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ab128218225d3542596ca3a02aee80d55494bef8)
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 411cc0e447..c676ee4e4e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1757,6 +1757,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index fb732d0a14..e2f1b09c60 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -875,7 +875,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -883,20 +882,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -909,8 +926,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -927,8 +942,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index b9e1528901..40fe5f6909 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -62,6 +62,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:15:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:15:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435355.688552 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1QC-0002UZ-AG; Wed, 02 Nov 2022 00:15:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435355.688552; Wed, 02 Nov 2022 00:15:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1QC-0002UR-6E; Wed, 02 Nov 2022 00:15:56 +0000
Received: by outflank-mailman (input) for mailman id 435355;
 Wed, 02 Nov 2022 00:15:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QA-0002UJ-SW
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QA-0003F3-Rr
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QA-0007od-RG
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:15:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=eRHY8fRLS88SNvpMdtp1Lcu0TEKQuJt8EA+uZMAcZDI=; b=QZbQVCdcNyR8WBLSt/BZjeeyHf
	OYIxbRGOa8uQoSdwOEyWz1KXw1lFo5jyqXjrp/sLzzMrFdUxHZTuio91Y5ixut41//SmkYj8KN6m9
	0xm8FIFJVjgPyJhi2WS0Uw4ZJY36nPuKyXuG4oc1l0d9bWjAWKmxRPbBtc4pehecZnW4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1oq1QA-0007od-RG@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:15:54 +0000

commit 074b32e47174a30bb751f2e2c07628eb56117eb8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 86 ++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 31 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c676ee4e4e..3907c35643 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1377,45 +1377,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name)
 static struct node *construct_node(struct connection *conn, const void *ctx,
 				   const char *name)
 {
-	struct node *parent, *node;
-	char *parentname = get_parent(ctx, name);
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
 
 	if (!parentname)
 		return NULL;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
 
-	/* Add child to parent. */
-	if (add_child(ctx, parent, name))
-		goto nomem;
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
 
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
 
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:16:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:16:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435356.688555 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1QM-0002XR-Ag; Wed, 02 Nov 2022 00:16:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435356.688555; Wed, 02 Nov 2022 00:16:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1QM-0002XJ-84; Wed, 02 Nov 2022 00:16:06 +0000
Received: by outflank-mailman (input) for mailman id 435356;
 Wed, 02 Nov 2022 00:16:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QL-0002X8-0s
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QL-0003Fy-0D
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QK-0007pH-U6
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=wdiuGxgFcquJDgvdkB9dnUYjY/8iZRD9QWJP16ySOeg=; b=U0KwzrLen83vIqK8qHadV8n5jH
	OQIRNX5p5oR3T7qE10VxPZfH/FyP/ntyZ0gyCV61YJqtqQoK7gbS8MBQomnjrKET1GQCurtDIFP1n
	gYfTlOsMLOJTPBvR3N5Wmb6eicZUmQllazufC9adbeOZynB+aECXZYjk6g8/eztEfBkY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1oq1QK-0007pH-U6@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:16:04 +0000

commit 32ff913afed898e6aef61626a58dc0bf5c6309ef
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4)
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 3907c35643..f433a45dc2 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1608,15 +1608,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1626,7 +1626,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2325,6 +2327,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2377,12 +2390,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2399,11 +2407,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:16:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:16:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435357.688559 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1QW-0002Zp-CH; Wed, 02 Nov 2022 00:16:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435357.688559; Wed, 02 Nov 2022 00:16:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1QW-0002Zh-9Z; Wed, 02 Nov 2022 00:16:16 +0000
Received: by outflank-mailman (input) for mailman id 435357;
 Wed, 02 Nov 2022 00:16:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QV-0002ZZ-48
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QV-0003Gm-3O
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1QV-0007pq-2Y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=kElj66QITKrWsND/xKe7ICOg8pzR3Hh7yp3ofQrI8QI=; b=IIV55cOgsUgvr4phYrMp9g0BGy
	grdIvCHjv0Y78x6BfM8FD3eoGKEJEGbxYVzcyrj0id1Ua/+xkzLYi+EAI74usVlKq513xs3CBi4ZY
	Or47lA9GfnI8XOsTcSghVAPSS2rHnDOFntmVq4YuVrt2faYrF/QcMauF6ulVzWfqqos0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: add generic treewalk function
Message-Id: <E1oq1QV-0007pq-2Y@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:16:15 +0000

commit 01ab4910229696e51c59a80eb86d0fedeeccb54b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d7c5d19bc27492360196e7dad2b227908564fff)
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f433a45dc2..2cda3ee375 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1838,6 +1838,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2305,18 +2434,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2376,7 +2493,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index bfd3fc1e9d..2d9942171d 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -202,6 +202,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -338,6 +339,45 @@ void read_state_buffered_data(const void *ctx, struct connection *conn,
 			      const struct xs_state_connection *sc);
 void read_state_node(const void *ctx, const void *state);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:16:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:16:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435358.688563 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Qg-0002cj-Dv; Wed, 02 Nov 2022 00:16:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435358.688563; Wed, 02 Nov 2022 00:16:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Qg-0002cb-B8; Wed, 02 Nov 2022 00:16:26 +0000
Received: by outflank-mailman (input) for mailman id 435358;
 Wed, 02 Nov 2022 00:16:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qf-0002cF-7T
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qf-0003HE-6e
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qf-0007qF-5p
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=zxN9cdQHOzzcXVobN051JAL5QfBfl54Pxi3gY1oLmec=; b=FeAtrIsv/mTOiV1dMoNNXxZAFO
	a0ACPFOM3w1ZgUPgEhKVTe1Rhjc8pAyUxrjHffXgszAshrilwPdTV6/yw7hy8d2Be22CklyigKFbq
	U/RCB5uCq4ZKnEFx/if1gOeveaZJTYNuD5CsaU0TljLAzJGTo0dbucKS59JNijUSDEME=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: simplify check_store()
Message-Id: <E1oq1Qf-0007qF-5p@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:16:25 +0000

commit c5a76df793c638423e1388528dc679a3e020a477
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 70f719f52a220bc5bc987e4dd28e14a7039a176b)
---
 tools/xenstore/xenstored_core.c | 47 +++++++++++++----------------------------
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2cda3ee375..760f3c16c7 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2477,50 +2477,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-		if (!children) {
-			log("check_store create table: ENOMEM");
-			return ENOMEM;
-		}
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2530,19 +2514,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:16:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:16:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435359.688567 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Qq-0002gM-Gt; Wed, 02 Nov 2022 00:16:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435359.688567; Wed, 02 Nov 2022 00:16:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Qq-0002gF-E7; Wed, 02 Nov 2022 00:16:36 +0000
Received: by outflank-mailman (input) for mailman id 435359;
 Wed, 02 Nov 2022 00:16:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qp-0002g0-AE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qp-0003HX-9d
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qp-0007qe-92
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8UcD2CObvnscOKKkqGjgHcCE9eOqeS7HcV2sn+Xg4Rc=; b=V2o20NedTQBu+zKVERtckruFAl
	3gRTySc6zD+BkZt+XTHR6FiQ4ZkDISa11jRv1T+RpwAHKeJrH/Jtr2YBH50jQzYOjVtFcd78rYhzA
	kMDTl6LTWWAaJm9qs8SEEZVLnCJ9/WHXcFoSTYt4lGfvqAXZcDzq12tNK7+kFGzrypIU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: use treewalk for check_store()
Message-Id: <E1oq1Qp-0007qe-92@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:16:35 +0000

commit f5a4c26b2efc55a5267840fcb31f95c00cc25d10
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 760f3c16c7..efdd1888fd 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2444,18 +2444,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2469,70 +2457,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
+	struct hashtable *reachable = arg;
 
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
-
-			childnode = read_node(NULL, childname, childname);
-
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2581,24 +2528,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char * root = talloc_strdup(NULL, "/");
-	struct hashtable * reachable =
-		create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
+
+	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
 		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:16:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:16:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435360.688573 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1R0-0002jB-KB; Wed, 02 Nov 2022 00:16:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435360.688573; Wed, 02 Nov 2022 00:16:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1R0-0002j3-Fm; Wed, 02 Nov 2022 00:16:46 +0000
Received: by outflank-mailman (input) for mailman id 435360;
 Wed, 02 Nov 2022 00:16:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qz-0002im-DH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qz-0003JU-Ca
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Qz-0007r5-By
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=PpGiGisJxtzZVe51YcnOx5MCGrOs64MzQvFPBMqhIYY=; b=ziPYjVj3qP6zT+HfkhWtF5XlBR
	q7h9D2QlxIStkG8MEH3vvptwJqpeHCtHzJTsyq3+xgN8cS0A2c33xoXZj4tXfW3pf/q7e7WhSLZnX
	f5lGR9AFzoTWsXY31goj9HvcjoBQ0Gt6zgQX6QLlWWENTeoUXXG8oRy7ihdfLfvECEPU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1oq1Qz-0007r5-By@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:16:45 +0000

commit 1514de3a5f23aef451133367d8dc04a26b88052f
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ea16962053a6849a6e7cada549ba7f8c586d85c6)
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index efdd1888fd..58fb651542 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1334,21 +1334,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1619,69 +1604,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1689,9 +1664,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1728,7 +1715,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:16:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:16:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435361.688575 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1RA-0002m5-K0; Wed, 02 Nov 2022 00:16:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435361.688575; Wed, 02 Nov 2022 00:16:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1RA-0002lx-HM; Wed, 02 Nov 2022 00:16:56 +0000
Received: by outflank-mailman (input) for mailman id 435361;
 Wed, 02 Nov 2022 00:16:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1R9-0002lk-GU
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1R9-0003Je-Fq
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1R9-0007rW-Ey
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:16:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=jARP3OJy3WgAzyS/UUSxQRv+PM3qcWJ7P45xGjMuaPI=; b=mT/hhWrCq/a40LEGdvsEIzwn2A
	goRD8dWjWHGP8tGDykgR/TKwmNEkFU2AcsKW/C4zRSWBPU6nIek7Wh5keBe/xgg2F1GKxlQOnZUJq
	mw+Ijjg0kMf0qhnLA1x8WCnyE1WLYX+MW68ltXBEwyXl7/E9rt0koBZzrKGX0MOZrFVg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: use treewalk for creating node records
Message-Id: <E1oq1R9-0007rW-Ey@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:16:55 +0000

commit 7682de61a49f7692cbd31a62f12c0ca12e069575
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: use treewalk for creating node records
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when creating the node records during a live update.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 297ac246a5d8ed656b349641288f3402dcc0251e)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++++++-------------------------
 1 file changed, 40 insertions(+), 65 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 58fb651542..05d349778b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -3120,101 +3120,76 @@ const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
 	return NULL;
 }
 
-static const char *dump_state_node_tree(FILE *fp, char *path,
-					unsigned int path_max_len)
+struct dump_node_data {
+	FILE *fp;
+	const char *err;
+};
+
+static int dump_state_node_err(struct dump_node_data *data, const char *err)
 {
-	unsigned int pathlen, childlen, p = 0;
+	data->err = err;
+	return WALK_TREE_ERROR_STOP;
+}
+
+static int dump_state_node(const void *ctx, struct connection *conn,
+			   struct node *node, void *arg)
+{
+	struct dump_node_data *data = arg;
+	FILE *fp = data->fp;
+	unsigned int pathlen;
 	struct xs_state_record_header head;
 	struct xs_state_node sn;
-	TDB_DATA key, data;
-	const struct xs_tdb_record_hdr *hdr;
-	const char *child;
 	const char *ret;
 
-	pathlen = strlen(path) + 1;
-
-	set_tdb_key(path, &key);
-	data = tdb_fetch(tdb_ctx, key);
-	if (data.dptr == NULL)
-		return "Error reading node";
-
-	/* Clean up in case of failure. */
-	talloc_steal(path, data.dptr);
-
-	hdr = (void *)data.dptr;
+	pathlen = strlen(node->name) + 1;
 
 	head.type = XS_STATE_TYPE_NODE;
 	head.length = sizeof(sn);
 	sn.conn_id = 0;
 	sn.ta_id = 0;
 	sn.ta_access = 0;
-	sn.perm_n = hdr->num_perms;
+	sn.perm_n = node->perms.num;
 	sn.path_len = pathlen;
-	sn.data_len = hdr->datalen;
-	head.length += hdr->num_perms * sizeof(*sn.perms);
+	sn.data_len = node->datalen;
+	head.length += node->perms.num * sizeof(*sn.perms);
 	head.length += pathlen;
-	head.length += hdr->datalen;
+	head.length += node->datalen;
 	head.length = ROUNDUP(head.length, 3);
 
 	if (fwrite(&head, sizeof(head), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node head error");
 	if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node state error");
 
-	ret = dump_state_node_perms(fp, hdr->perms, hdr->num_perms);
+	ret = dump_state_node_perms(fp, node->perms.p, node->perms.num);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
+
+	if (fwrite(node->name, pathlen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node path error");
 
-	if (fwrite(path, pathlen, 1, fp) != 1)
-		return "Dump node path error";
-	if (hdr->datalen &&
-	    fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1)
-		return "Dump node data error";
+	if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node data error");
 
 	ret = dump_state_align(fp);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
 
-	child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen;
-
-	/*
-	 * Use path for constructing children paths.
-	 * As we don't write out nodes without having written their parent
-	 * already we will never clobber a part of the path we'll need later.
-	 */
-	pathlen--;
-	if (path[pathlen - 1] != '/') {
-		path[pathlen] = '/';
-		pathlen++;
-	}
-	while (p < hdr->childlen) {
-		childlen = strlen(child) + 1;
-		if (pathlen + childlen > path_max_len)
-			return "Dump node path length error";
-		strcpy(path + pathlen, child);
-		ret = dump_state_node_tree(fp, path, path_max_len);
-		if (ret)
-			return ret;
-		p += childlen;
-		child += childlen;
-	}
-
-	talloc_free(data.dptr);
-
-	return NULL;
+	return WALK_TREE_OK;
 }
 
 const char *dump_state_nodes(FILE *fp, const void *ctx)
 {
-	char *path;
-
-	path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX + 1);
-	if (!path)
-		return "Path buffer allocation error";
+	struct dump_node_data data = {
+		.fp = fp,
+		.err = "Dump node walk error"
+	};
+	struct walk_funcs walkfuncs = { .enter = dump_state_node };
 
-	strcpy(path, "/");
+	if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data))
+		return data.err;
 
-	return dump_state_node_tree(fp, path, XENSTORE_ABS_PATH_MAX + 1);
+	return NULL;
 }
 
 void read_state_global(const void *ctx, const void *state)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:17:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:17:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435362.688579 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1RK-0002qY-Lz; Wed, 02 Nov 2022 00:17:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435362.688579; Wed, 02 Nov 2022 00:17:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1RK-0002qR-Ix; Wed, 02 Nov 2022 00:17:06 +0000
Received: by outflank-mailman (input) for mailman id 435362;
 Wed, 02 Nov 2022 00:17:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1RJ-0002qK-Jd
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1RJ-0003K2-Iz
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1RJ-0007s4-II
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=jIqjtPlxK94Z1D4C7UGooULefmsmTK5eKlyzlX6JZkg=; b=oYE5hIddAfeKbaL1aPG1A9g7s3
	LPGIjBJmvntCDglDaQvZwagKVMw2cgaOJ1qVntyTn/7xFaTIYbfiAWd5NZ6aacQhyGKc2urkmfL42
	dfP8mjcKw54chnZx7dHNRI0x6IzflyTVZD+vMxv50KUi3dNl6aCnKCkuXAIA4bJDFVM8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1oq1RJ-0007s4-II@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:17:05 +0000

commit 825332daeac9fc3ac1e482e805ac4a3bc1e1ab34
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 755d3f9debf8879448211fffb018f556136f6a79)
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 84 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 80 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 05d349778b..0ca1a5a19a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -80,6 +80,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -757,7 +758,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -800,7 +801,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1651,7 +1652,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1715,7 +1716,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2639,6 +2640,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2663,6 +2666,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 #ifndef NO_LIVE_UPDATE
@@ -2742,7 +2746,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2778,6 +2782,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2d9942171d..725793257e 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -240,6 +240,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(bool live_update);
 struct connection *new_connection(const struct interface_funcs *funcs);
 struct connection *get_connection_by_id(unsigned int conn_id);
@@ -286,6 +289,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index e2f1b09c60..8b134017a2 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -227,10 +227,64 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		set_tdb_key(node->name, &key);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -851,15 +905,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -920,23 +974,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -954,15 +996,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1081,7 +1123,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 40fe5f6909..5454e925ad 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -61,7 +61,7 @@ const char *get_implicit_path(const struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:17:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:17:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435363.688583 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1RU-0002to-Pi; Wed, 02 Nov 2022 00:17:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435363.688583; Wed, 02 Nov 2022 00:17:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1RU-0002tg-N1; Wed, 02 Nov 2022 00:17:16 +0000
Received: by outflank-mailman (input) for mailman id 435363;
 Wed, 02 Nov 2022 00:17:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1RT-0002tX-Mk
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1RT-0003KC-Lz
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1RT-0007sV-LK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=EMX19lkqFb4FVJ6lDdbQPr20EbpF8gR+OZa+QYpyWrs=; b=HsJlFl+sPaAh91lPdYig0lNQ+C
	WlGQNFwNQCljMCWhHqeys/y3IW4oU8/QF1SHSIwP1tOMW34zkxKHkLbJJNHTIbIUEhWnYOvIgsoIe
	9RaZTVMCjKyI+gP5NW+HOkg2MXZE5rxQc7PlXlDIrVWqzJ1oBTvz/bMkgUg3wWHA4rE4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: make the internal memory data base the default
Message-Id: <E1oq1RT-0007sV-LK@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:17:15 +0000

commit 8b81fc185ab13feca2f63eda3792189e5ac11a97
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d174fefa90487ddd25ebc618028f67b2e8a1f795)
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 11ebf79e6d..8d1d1a4f1e 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -223,9 +223,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom->guest_domid = domid;
     dom->cmdline = xc_dom_strdup(dom, cmdline);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 0ca1a5a19a..041124d8b7 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2329,7 +2329,7 @@ static void accept_connection(int sock)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2639,7 +2639,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2665,7 +2666,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2746,7 +2747,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2780,7 +2782,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:17:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:17:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435364.688587 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Re-00030j-RS; Wed, 02 Nov 2022 00:17:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435364.688587; Wed, 02 Nov 2022 00:17:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Re-00030b-Od; Wed, 02 Nov 2022 00:17:26 +0000
Received: by outflank-mailman (input) for mailman id 435364;
 Wed, 02 Nov 2022 00:17:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rd-00030P-PY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rd-0003KJ-Ow
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rd-0007t6-OJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=DKDQqgPRSi0uDhxspy+vbkREcpxoLFwEhqyupNVkvQU=; b=dRrh5fsGslra+YJG1nEeJgwf50
	YbBeSBnRuKRpU/Vq7cyfNQ+UYvVx3LSgJScIy4QRS46QPHeEgapyfSqcexm8GpBWY8BN0Q25SsutM
	levoU/Z/CFu7wBOrlmhyNooGbr3pgV/S0A/UlfgACJi48Krbq+1Ct8MYwtJ0cPQkerxU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] docs: enhance xenstore.txt with permissions description
Message-Id: <E1oq1Rd-0007t6-OJ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:17:25 +0000

commit 1f5b394d6ed0ee26b5878bd0cdf4a698bbc4294f
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d084d2c6dff7044956ebdf83a259ad6081a1d921)
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index a7d006519a..eccd596ee3 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:17:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:17:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435365.688591 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ro-00033K-Sp; Wed, 02 Nov 2022 00:17:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435365.688591; Wed, 02 Nov 2022 00:17:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ro-00033C-QB; Wed, 02 Nov 2022 00:17:36 +0000
Received: by outflank-mailman (input) for mailman id 435365;
 Wed, 02 Nov 2022 00:17:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rn-000335-SW
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rn-0003KT-Rt
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rn-0007tV-RB
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=APhKrOVrEnPuoFbf1aVK1NcNWn0p7C2cIIy/2RRhnUc=; b=cbJ2x/q7lKE38HIq5s44dsAick
	oPXOuuLKPaobFsLs0N70fv2iyNq8tMOMZIWUJ17zHzrDq5i3IdAqhtfzpY14KY4F/zqz79G6SmkNv
	pJWKVPJdvquzm0xMbpLzyNYxs7NjDN/MsZYrIVOIqYMqPwy9pqZQjFxiqsLhyck3H/90=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1oq1Rn-0007tV-RB@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:17:35 +0000

commit 5b0919f2c0e5060f6e0bc328f100abae0a9f07b8
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit db471408edd46af403b8bd44d180a928ad7fbb80)
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 20e67b1427..70f0c83de4 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -87,10 +87,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; SymbolMap.iter (fun _ -> recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid _ node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = SymbolMap.map walk node.children }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			SymbolMap.map walk node.children |> SymbolMap.filter is_valid } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -444,11 +455,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:17:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:17:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435366.688595 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ry-00035v-Ue; Wed, 02 Nov 2022 00:17:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435366.688595; Wed, 02 Nov 2022 00:17:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1Ry-00035n-Rf; Wed, 02 Nov 2022 00:17:46 +0000
Received: by outflank-mailman (input) for mailman id 435366;
 Wed, 02 Nov 2022 00:17:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rx-00035d-VR
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rx-0003Kw-Um
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1Rx-0007tu-U1
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=bFO6iY3jiLAHF+DjGBg/ZXr8ip1sbMT2pBMEqQcpg9c=; b=gzzbngjGXU4IlEZYqdamHhUYby
	O1VJ3M8eQYNQR0joaJHa8ZpnqVf6QL3ZcOSd92VetxOnjzmW8cFmjRTVmRYeas2p+5t10kRR2CDl/
	EG8va5U3m+qzMw5rrEm72mE5Jgjk045VVV6ISQVfeIgJuDTalziUdfn1u7fxt7SW4zSg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1oq1Rx-0007tu-U1@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:17:45 +0000

commit 635390415f4a9c0621330f0b40f8c7e914c4523f
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3)
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index ce39ce28b5..6cb990ee7f 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -722,7 +722,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:17:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:17:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435367.688598 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1S8-000397-Vo; Wed, 02 Nov 2022 00:17:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435367.688598; Wed, 02 Nov 2022 00:17:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1S8-00038j-TC; Wed, 02 Nov 2022 00:17:56 +0000
Received: by outflank-mailman (input) for mailman id 435367;
 Wed, 02 Nov 2022 00:17:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1S8-00038V-2E
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1S8-0003L0-1Q
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1S8-0007uJ-0f
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:17:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=xEUhQSylvPSKZPrReSnwOvLMIZB5RYxgwN6HPZpzeac=; b=Z16BxqigSYvjsdvF36GWjq+oXh
	rOpwq9TDNajCkcUmF1hDjo+V4QnmJnZkki3qg9cZWgGLVOu6SC9Dth1YlMrLHJREaudf1cs2AXyZD
	X14OOX0uOUGFfz0rFubtvWU+xDkW90tFeVkG2BjmFNydLti5hX7TKPb6cxS0YK6NtqdA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: fix deleting node in transaction
Message-Id: <E1oq1S8-0007uJ-0f@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:17:56 +0000

commit 4305807dfdc183f4acd170fe00eb66b338fa6430
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187)
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 3e3eb47326..7ffe21bb52 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -418,7 +418,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:18:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:18:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435369.688603 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1SJ-0003C7-1b; Wed, 02 Nov 2022 00:18:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435369.688603; Wed, 02 Nov 2022 00:18:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq1SI-0003Bz-Uj; Wed, 02 Nov 2022 00:18:06 +0000
Received: by outflank-mailman (input) for mailman id 435369;
 Wed, 02 Nov 2022 00:18:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1SI-0003Bk-56
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:18:06 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1SI-0003LH-4T
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:18:06 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq1SI-0007uw-3e
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:18:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Sf9AzE/cLM1k49DXes/Hl85E95ZcBBVrlAmvp+/LU9o=; b=Xxdzcrk8zI8iMft9dg26t/Tb6C
	E5xx8yL5t6wiD6z5UhmWOMphZasGF874yHOOsnmsn9+CdtiDsoL9XrqJ0N80Z9Uv8IU/7zfzAULwB
	jdB1yNB0z/6VxWQALY7DMMcX3Z3uHav9cjcx9FK//Ov3zDfXph/G7H6HMal8rlLnMtmo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1oq1SI-0007uw-3e@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:18:06 +0000

commit 1bdd7c438b399e2ecce9e3c72bd7c1ae56df60f8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 14:07:24 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff)
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 041124d8b7..ccb7f0a925 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -727,8 +727,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -846,10 +845,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 unsigned int perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 7ffe21bb52..ac854197ca 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -199,25 +200,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -240,7 +236,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -259,10 +254,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -273,9 +264,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -302,7 +294,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -321,7 +313,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -333,7 +325,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -371,100 +362,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -556,6 +537,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -579,13 +561,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -660,7 +646,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -672,11 +658,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:55:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:55:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435370.688608 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq223-0007wT-QE; Wed, 02 Nov 2022 00:55:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435370.688608; Wed, 02 Nov 2022 00:55:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq223-0007wH-Mw; Wed, 02 Nov 2022 00:55:03 +0000
Received: by outflank-mailman (input) for mailman id 435370;
 Wed, 02 Nov 2022 00:55:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq222-0007wB-0Y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq221-0003up-V0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq221-00019m-Tf
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=jjt8JlCl9P53yiSMQTCjzFj0QyHG0PRl2jIMm19xvjM=; b=hwoNTC7GFIoYR4KTGbRjPBbwBA
	AwAPIgzWhWtdV/UcIuaJerauG8xeIx0w7olKObPf/5wq710UykH7//RqTYi/6zCUWtY7UBdeXsag4
	CBgEz9ewVzKAu5Wi34vFMbR7e4rYlsVNwNQXUu6mDb1ofwpFD5Rsm0McPTXFZouRtHgw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1oq221-00019m-Tf@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:55:01 +0000

commit ee03d9b56e6141422b4ef2444f93cf2e88e6a26c
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 1cd3cc7ea27cda7640a8d895e09617b61c265697)
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9172dd7671..a00c49e404 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1054,9 +1054,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -1065,7 +1064,7 @@ static int destroy_node(void *_node)
 	set_tdb_key(node->name, &key);
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -1074,7 +1073,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1096,23 +1096,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:55:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:55:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435371.688611 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22D-0007yy-RW; Wed, 02 Nov 2022 00:55:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435371.688611; Wed, 02 Nov 2022 00:55:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22D-0007yo-Ob; Wed, 02 Nov 2022 00:55:13 +0000
Received: by outflank-mailman (input) for mailman id 435371;
 Wed, 02 Nov 2022 00:55:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22C-0007yJ-5j
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22C-0003ut-4v
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22C-0001AN-15
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=KXB0R8d0nNbHqLQUPKLZRyzDXGgEPgGqkEdhggLOH4k=; b=dwNIEJt9O+tYNIZS5qCYrmAIvy
	QgJi/fYaEXUzkT17HUiovLjRuXGtZx74x8GGSEPs5Yjy6XHZl+AoFj66tSOS1Yu6wejb+Fn4V/4ke
	dGDrpKAFsqtmiH2/SCALyLP751ECOGBdPKZuFtpmXCuuflVR2ZOzTeYhlFx8RNnmvJJw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1oq22C-0001AN-15@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:55:12 +0000

commit 579e7334b909c22efc65c5df22e8afe414882154
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34)
---
 tools/xenstore/xenstored_core.c        | 23 +++++++++++++++--------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index a00c49e404..b28c2c66b5 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -531,15 +531,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
@@ -1056,16 +1058,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	set_tdb_key(node->name, &key);
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 0c9a0961b5..900336afa4 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -148,6 +148,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd07fb0f21..faf6c930e4 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:55:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:55:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435376.688625 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22O-0008I2-9L; Wed, 02 Nov 2022 00:55:24 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435376.688625; Wed, 02 Nov 2022 00:55:24 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22O-0008Hu-6C; Wed, 02 Nov 2022 00:55:24 +0000
Received: by outflank-mailman (input) for mailman id 435376;
 Wed, 02 Nov 2022 00:55:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22M-0008HC-94
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22M-0003vG-8L
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22M-0001Aq-7J
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=/OadLm2kuf1tSsqQMiO0qB2ZuxJDj1IfYTNl+Kt6Eik=; b=5vR0KrhKNeEEHsroCiPZwA3wG1
	Wx9QgdbcF9TUn64CrW7+s1LfQAXEcIz4IyugB6y/N+ctgu5xv2iWCpuISv8AGZfHd5/DFEMlLbgtM
	EIuTr0UgG0ARZOIyoYd99GGrkWkxXVd5EFedsiWQw0ZxP3fzxhal6DMF4KLLMMQKYens=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: split up send_reply()
Message-Id: <E1oq22M-0001Aq-7J@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:55:22 +0000

commit 0d8bea403d4d1763dddb0c1c81d30efebafb6962
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32)
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 39 ++++-----------------
 3 files changed, 52 insertions(+), 62 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b28c2c66b5..01d4a2e440 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -733,49 +733,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -783,8 +766,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 900336afa4..38d97fa081 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -180,6 +180,7 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index db89e0141f..a116f967dc 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -85,35 +85,6 @@ static const char *get_watch_path(const struct watch *watch, const char *name)
 	return path;
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
-{
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
-
-	name = get_watch_path(watch, name);
-
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
-}
-
 /*
  * Check permissions of a specific watch to fire:
  * Either the node itself or its parent have to be readable by the connection
@@ -190,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -292,7 +267,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:55:34 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:55:34 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435377.688630 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22Y-000092-Ac; Wed, 02 Nov 2022 00:55:34 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435377.688630; Wed, 02 Nov 2022 00:55:34 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22Y-00008t-7l; Wed, 02 Nov 2022 00:55:34 +0000
Received: by outflank-mailman (input) for mailman id 435377;
 Wed, 02 Nov 2022 00:55:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22W-0008OG-CQ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22W-0003vT-Bd
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22W-0001BF-Ad
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=hou0xiuDHInz9HMS27FZJxvoV+rniBrrunVCH9A8Ntg=; b=ww/KcBPzVnpUIdEid3h53Ll27o
	DWMrpmya1ZnXsjdqzjpuEqO8AC8Pdma1vfi9Y4/4syOSYoblAIbgYEY14PZKXcf1XUuaqeESPXjFx
	pL1Z4WsKDQeVTYcMjg5GA/XPbOo/LWeKscHLEtKDBc6SDFahDDi38fGkIca4JuTg9eYA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1oq22W-0001BF-Ad@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:55:32 +0000

commit b322923894ea23f397efc58a938cb9213d7dc617
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ead062a68a9c201a95488e84750a70a107f7b317)
---
 tools/xenstore/xenstored_core.c   | 26 +++++++++++++++++---------
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c |  7 +------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 01d4a2e440..6498bf6036 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -211,6 +211,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -254,8 +269,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
@@ -1472,18 +1486,12 @@ static struct {
  */
 static void ignore_connection(struct connection *conn)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored\n", conn);
 
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 38d97fa081..0ba5b783d4 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -270,6 +270,8 @@ int remember_string(struct hashtable *hash, const char *str);
 
 void set_tdb_key(const char *name, TDB_DATA *key);
 
+void conn_free_buffered_data(struct connection *conn);
+
 const char *dump_state_global(FILE *fp);
 const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 				     const struct connection *conn,
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3d4d0649a2..72a5cd3b9a 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -417,15 +417,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:55:44 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:55:44 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435379.688634 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22i-0000Mg-CL; Wed, 02 Nov 2022 00:55:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435379.688634; Wed, 02 Nov 2022 00:55:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22i-0000MY-9F; Wed, 02 Nov 2022 00:55:44 +0000
Received: by outflank-mailman (input) for mailman id 435379;
 Wed, 02 Nov 2022 00:55:42 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22g-0000Lf-GM
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22g-0003vy-Fg
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22g-0001Bn-Dy
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=CqcTGe3nQ+7+qcwaPrOQXp+gGNoAUSR9EtVlEFOvFDU=; b=2HKfCED6kjQcBWsS3gvQA3okST
	krEKgYs47HvoBiCu15aJvQLvub6h+P+Tt2TFWv+3vutz1E1+QPW8juf6A+10cdW+JG1j797os9o4j
	ClfNoEc5IUsK0orOYcRZdxrk0CF7eOB1ml9KrT2KQpm/UWqkEVxB/IeAso+QF2uAVxhk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: reduce number of watch events
Message-Id: <E1oq22g-0001Bn-Dy@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:55:42 +0000

commit 8999db805e5ef55172a85d67695429edc3d78771
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297)
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 6498bf6036..5157a7527f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1261,7 +1261,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1273,7 +1273,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1285,7 +1285,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1311,13 +1316,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index faf6c930e4..54432907fc 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -323,6 +327,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index a116f967dc..bc6d833028 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:55:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:55:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435383.688638 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22r-0000XD-Fj; Wed, 02 Nov 2022 00:55:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435383.688638; Wed, 02 Nov 2022 00:55:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq22r-0000X6-Cs; Wed, 02 Nov 2022 00:55:53 +0000
Received: by outflank-mailman (input) for mailman id 435383;
 Wed, 02 Nov 2022 00:55:52 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22q-0000Wr-JU
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:52 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22q-0003w9-Ii
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:52 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq22q-0001CL-Hz
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:55:52 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=1NYn8XmrfAHeHZbNvqcfZJNUpMRqkxUEAtxp1waYZ6g=; b=mTyrpc4yFq8YTrSKnUMQ6d4dMT
	Ya7DKEbtZGOtaAqtagoIOefYKO1Lf40/EDM9h83jrvoV0Xjzq4DLw7LO3mPmSutiq3i7I8kJl3HPw
	je9iKW3ZARc6kNHOIrW6OXtRUf/1ayYjd0Qo5GFBIZWK4VY6lCt7EXTdn06i6ZBoV+L4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: let unread watch events time out
Message-Id: <E1oq22q-0001CL-Hz@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:55:52 +0000

commit 53a77b82717530d836300f1de0ad037de85477dd
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 5285dcb1a5c01695c11e6397c95d906b5e765c98)
---
 tools/xenstore/xenstored_core.c | 133 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5157a7527f..ee3396fefa 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -108,6 +108,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -211,19 +213,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -382,6 +457,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -402,10 +478,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (domain_can_read(conn) ||
 			    (domain_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -760,6 +838,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -811,6 +890,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -2099,6 +2184,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2121,6 +2209,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2135,6 +2224,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2149,7 +2271,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:U", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2198,6 +2320,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
@@ -2642,6 +2767,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 		barf("error restoring buffered data");
 
 	memcpy(bdata->buffer, data, len);
+	if (bdata->hdr.msg.type == XS_WATCH_EVENT && timeout_watch_event_msec &&
+	    domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 0ba5b783d4..2db577928f 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <dirent.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -67,6 +68,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -110,6 +113,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -237,6 +241,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:56:03 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:56:03 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435385.688642 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq231-0000bp-In; Wed, 02 Nov 2022 00:56:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435385.688642; Wed, 02 Nov 2022 00:56:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq231-0000bi-En; Wed, 02 Nov 2022 00:56:03 +0000
Received: by outflank-mailman (input) for mailman id 435385;
 Wed, 02 Nov 2022 00:56:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq230-0000bW-Mm
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq230-0003wW-M6
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq230-0001D2-L8
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sA33zLDEoNd8qbheNu0cbdLzjI1I9PKcpZz6fiWuxl4=; b=FpYq2mgSJypRgSIl7y5fZguNn5
	WHjLnJpkDqDw1BT7Q4c3+X3DAGI9Rvfd1cBVsfOpKA4s7qW78G9Zw8IRX0o/hp0/y6R9oajjX3C46
	g+prm9Idk474kNihbDXxZdIrX42xCNM2W82bRTp+8ClDgvVQrDJLfiy+c+Y0F6diTvGQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: limit outstanding requests
Message-Id: <E1oq230-0001D2-L8@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:56:02 +0000

commit 56300e8e1781cee1b6a514e5f2bea234a7885d55
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 36de433a273f55d614c83b89c9a8972287a1e475)
---
 tools/xenstore/xenstored_core.c   | 88 +++++++++++++++++++++++++++++++++++++--
 tools/xenstore/xenstored_core.h   | 20 ++++++++-
 tools/xenstore/xenstored_domain.c | 38 ++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 +++++--
 5 files changed, 150 insertions(+), 14 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ee3396fefa..d871f217af 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -107,6 +107,7 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -223,12 +224,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -244,6 +257,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -399,6 +436,7 @@ int delay_request(struct connection *conn, struct buffered_data *in,
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -412,6 +450,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -859,6 +902,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -866,7 +911,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -896,8 +942,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1658,6 +1709,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1727,6 +1779,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
 	new->is_ignored = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 	INIT_LIST_HEAD(&new->delayed);
@@ -2184,6 +2237,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2209,6 +2265,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2257,6 +2314,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2271,8 +2342,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
-				  NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
 			no_domain_init = true;
@@ -2320,6 +2391,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
@@ -2776,6 +2850,14 @@ static void add_buffered_data(struct buffered_data *bdata,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	/*
+	 * Watch events are never "outstanding", but the request causing them
+	 * are instead kept "outstanding" until all watch events caused by that
+	 * request have been delivered.
+	 */
+	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
+		domain_outstanding_inc(conn);
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2db577928f..fcb27399f1 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -56,6 +56,8 @@ struct xs_state_connection;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -63,6 +65,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -115,6 +128,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -184,7 +200,8 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -240,6 +257,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 72a5cd3b9a..979f8c6298 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -78,6 +78,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -287,8 +290,12 @@ bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	if (conn->is_ignored)
 		return false;
@@ -337,7 +344,7 @@ static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -398,9 +405,6 @@ static int new_domain(struct domain *domain, int port, bool restore)
 	domain->conn->domain = domain;
 	domain->conn->id = domain->domid;
 
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
-
 	return 0;
 }
 
@@ -944,6 +948,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index dc97591713..5757a65571 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -68,6 +68,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index bc6d833028..1d664e3d6b 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -269,8 +272,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	trace_create(watch, "watch");
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:56:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:56:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435386.688646 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23B-0000f2-Jp; Wed, 02 Nov 2022 00:56:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435386.688646; Wed, 02 Nov 2022 00:56:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23B-0000et-Ge; Wed, 02 Nov 2022 00:56:13 +0000
Received: by outflank-mailman (input) for mailman id 435386;
 Wed, 02 Nov 2022 00:56:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23A-0000ej-Q1
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23A-0003wj-PH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23A-0001DR-OT
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=rBF+BukCLra1s4mzOpPmpRvzTdLYtlgUuKkqZyZaz1o=; b=2YuImC253RxLScAuoADKP6Krb9
	96J4RYgR7YhUO8HODgVMkYrUHa9KRq7XgAFJTcsmHhFWWhTQTkrjFJDMC87nSuL07q3ADM1l1oSDe
	8mjfVKniWaxc40vAS0L/zBQmrzDp3M0+XLxB4LXgAdUzeBhAysL0U+smKKVP+Dd6wbbo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1oq23A-0001DR-OT@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:56:12 +0000

commit 97c251f953c58aec7620499ac12924054b7cd758
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2)
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index d871f217af..6ea06e20df 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -882,6 +882,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -914,7 +915,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -936,12 +937,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index fcb27399f1..afbd982c26 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -62,6 +62,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:56:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:56:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435387.688650 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23L-0000jw-NO; Wed, 02 Nov 2022 00:56:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435387.688650; Wed, 02 Nov 2022 00:56:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23L-0000jp-KU; Wed, 02 Nov 2022 00:56:23 +0000
Received: by outflank-mailman (input) for mailman id 435387;
 Wed, 02 Nov 2022 00:56:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23K-0000jj-T2
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23K-0003wt-SE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23K-0001Du-Ra
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=wpQ2tQ3bp6VaEwXNuDJy6Q2Gut3+kE3F7+ez0KCFiRY=; b=gvc9Irw5jBeQFEOMjI2gbItm+T
	rJ3CBsrU+ArFMUOOBz3XhakYUOBWzFFTmT3VBfIZApNqt8X3zjnAr7lKTuTHDF6GNoxNfSOGm3lTE
	Jv+BrFHcF0cPmm4okraL+YYi8dUdUg8hy2ubIlsTY/XwbISTEp1ro/jEF7wYRgXXrcFY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: fix connection->id usage
Message-Id: <E1oq23K-0001Du-Ra@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:56:22 +0000

commit 3e51699fcc578c7c005fd4add70cf7c8117d0af9
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831)
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 8e470f2b20..211fe1fd9b 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -821,7 +821,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	unsigned int cmd, num, off;
 	char **vec = NULL;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	off = get_string(in, 0);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index afbd982c26..c0a056ce13 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -118,7 +118,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this connection ignored? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 54432907fc..ee1b09031a 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -477,7 +477,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:56:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:56:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435388.688654 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23V-0000my-Op; Wed, 02 Nov 2022 00:56:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435388.688654; Wed, 02 Nov 2022 00:56:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23V-0000mr-ML; Wed, 02 Nov 2022 00:56:33 +0000
Received: by outflank-mailman (input) for mailman id 435388;
 Wed, 02 Nov 2022 00:56:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23U-0000me-WA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23U-0003x7-VQ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23U-0001EJ-Uj
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=zdG0SqPpBPLjsx/TXwt4LPIC/C0+13wco/z5uzvqzuM=; b=lqu7MjQ8itWWAzfeLkY+84a2ne
	8TwnlI5rXnAMD+FVuX0SFnNWOxst0QqJ805v5/9lB5DLrrRMJf/91tfElNOzGPvgjMhUEoSsQbzb2
	I5nkorLaFgw0+ddqsBk9OoDpfL6flG6cI12avcx0uY1+JShlz47ToLfLg2IOeKrhMMZk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1oq23U-0001EJ-Uj@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:56:32 +0000

commit 8ee7ed7c1ef435f43edc08be07c036d81642d8e1
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit dbef1f7482894c572d90cd73d99ed689c891e863)
---
 tools/xenstore/xenstored_core.c        |  43 +++++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 4 files changed, 109 insertions(+), 51 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 6ea06e20df..85c0d2f38f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -603,7 +603,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -625,7 +625,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1238,13 +1238,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1294,8 +1298,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1580,10 +1588,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
+
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
 
-	if (write_node(conn, node, false))
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
@@ -3003,7 +3028,9 @@ void read_state_node(const void *ctx, const void *state)
 	set_tdb_key(name, &key);
 	if (write_node_raw(NULL, &key, node, true))
 		barf("write node error restoring node");
-	domain_entry_inc(&conn, node);
+
+	if (domain_entry_inc(&conn, node))
+		barf("node accounting error restoring node");
 
 	talloc_free(node);
 }
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 979f8c6298..3c27973fb8 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -369,6 +370,18 @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid)
 	return domain ? : alloc_domain(ctx, domid);
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port, bool restore)
 {
 	int rc;
@@ -788,30 +801,28 @@ void domain_deinit(void)
 		xenevtchn_unbind(xce_handle, virq_port);
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -847,7 +858,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -857,8 +868,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -877,25 +894,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -905,13 +922,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5757a65571..cce13d14f0 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -58,10 +58,10 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ee1b09031a..86caf6c398 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -519,8 +519,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:56:43 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:56:43 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435389.688659 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23f-0000qA-R9; Wed, 02 Nov 2022 00:56:43 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435389.688659; Wed, 02 Nov 2022 00:56:43 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23f-0000q1-O7; Wed, 02 Nov 2022 00:56:43 +0000
Received: by outflank-mailman (input) for mailman id 435389;
 Wed, 02 Nov 2022 00:56:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23f-0000pk-31
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23f-0003yy-2P
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23f-0001El-1a
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=2IGdLkY7ctRv9JnLBjmYn9NBJ+xkWS8Pcj6gDWpqDIA=; b=oyjmgYh/GfrXCRVyRQ/pVW6Cr/
	43OxhJDUd+70nPvMKrjPO3bzgVbQAtqnhRsaWzJjhhdhmd95cQLLqh3cnRVfPqRKnSEqVzjVbH7I8
	ty4iqinnhxx2bhVXBrrRJApuIgRWU0L6qiXb9TzkHwbXK4jngJkhuQaDt4tyLeffHPW8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1oq23f-0001El-1a@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:56:43 +0000

commit 1035371fee5552b8cfe9819c4058a4c9e695ba5e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 268369d8e322d227a74a899009c5748d7b0ea142)
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  1 +
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index a16e0c3807..bafc90e2f6 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -63,4 +63,8 @@
 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 85c0d2f38f..050d6f651a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -106,6 +106,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
 
@@ -560,6 +561,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -581,14 +583,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -603,19 +604,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -732,7 +750,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -795,7 +813,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1201,7 +1219,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1475,7 +1493,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1505,7 +1523,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2282,6 +2300,8 @@ static void usage(void)
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2367,6 +2387,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index c0a056ce13..1b3bd5ca56 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -261,6 +261,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 86caf6c398..7bd41eb475 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -260,6 +263,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -297,6 +305,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:56:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:56:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435390.688662 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23p-0000tI-Sc; Wed, 02 Nov 2022 00:56:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435390.688662; Wed, 02 Nov 2022 00:56:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23p-0000tA-Ph; Wed, 02 Nov 2022 00:56:53 +0000
Received: by outflank-mailman (input) for mailman id 435390;
 Wed, 02 Nov 2022 00:56:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23p-0000t0-6F
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23p-0003z8-5a
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23p-0001FD-4o
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:56:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=IT9J1j4MJ+TlM37B7SIx6ccXtce8khV7QDhx9WfAZmY=; b=3o/yrnu9zlbyWMExMdTKCSyfB+
	HgD+QMxRu7jiDyGgW1z9UqASRbcp1cY+odruyfY4xbN+ZzllBxx4YVyVUfs2GRj/tZhSCWLakbsIu
	JI+EdlsYSXshLNwBVzQyGjR1kjSJw5lmbft32dNFdHZYB0cFmyVBjqLlpxU6eDt8Ao64=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1oq23p-0001FD-4o@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:56:53 +0000

commit ccef72b6a885714dae0b6f1accb33042ee40e108
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 60e2f6020dea7f616857b8fc1141b1c085d88761)
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 3 +++
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 050d6f651a..51af74390c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1940,7 +1940,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -1979,7 +1980,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(bool live_update)
+void setup_structure(bool live_update)
 {
 	char *tdbname;
 
@@ -2002,6 +2003,7 @@ static void setup_structure(bool live_update)
 		manual_node("/", "tool");
 		manual_node("/tool", "xenstored");
 		manual_node("/tool/xenstored", NULL);
+		domain_entry_fix(dom0_domid, 3, true);
 	}
 
 	check_store();
@@ -2512,9 +2514,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure(live_update);
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init && !live_update) {
 		domain_init(-1);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1b3bd5ca56..459698d840 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -224,6 +224,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(bool live_update);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 struct connection *get_connection_by_id(unsigned int conn_id);
 void check_store(void);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3c27973fb8..0dd75a6a21 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -476,6 +476,9 @@ static struct domain *introduce_domain(const void *ctx,
 		}
 		domain->interface = interface;
 
+		if (is_master_domain)
+			setup_structure(restore);
+
 		/* Now domain belongs to its connection. */
 		talloc_steal(domain->conn, domain);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:57:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:57:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435391.688666 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23z-0000yq-Vb; Wed, 02 Nov 2022 00:57:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435391.688666; Wed, 02 Nov 2022 00:57:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq23z-0000yj-Sn; Wed, 02 Nov 2022 00:57:03 +0000
Received: by outflank-mailman (input) for mailman id 435391;
 Wed, 02 Nov 2022 00:57:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23z-0000yc-9b
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23z-0003zP-8v
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq23z-0001Fq-86
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ktwD1V97wckBKAhVxAbZcUql9rBHMB5dF4SpXUY/ZXY=; b=je6eAhALWsaIaQvu2u8Rx4eEKX
	dvWMcP0zPanqzDC6CQOaxBPW4csrMKvDqhzpKTb3BLbf9BsXtboH6nX0LbD6gEEFYycwH/Ab293e/
	5wcjzQ45yT41fwkk1m+e+h4SUnGHHqFJxS+oxKSQEOK+NVGkpmiBrTwBLdO4YN2azf+o=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1oq23z-0001Fq-86@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:57:03 +0000

commit aa29eb624797fb6825e4a23071c88417672868a4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d4a8ec7a93faedbe54fd197db146de628459e77)
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 51af74390c..eeb0d893e8 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -109,6 +109,8 @@ int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2304,7 +2306,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2331,6 +2340,7 @@ static struct option options[] = {
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2379,7 +2389,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2387,11 +2397,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2409,7 +2424,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2459,7 +2474,10 @@ int main(int argc, char *argv[])
 						 quota_max_path_len);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 459698d840..2fb37dbfe8 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -263,6 +263,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 0dd75a6a21..ec542df6a6 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -76,6 +76,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -296,6 +303,9 @@ bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	if (conn->is_ignored)
@@ -956,6 +966,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index cce13d14f0..571aa46d15 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,6 +65,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:57:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:57:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435392.688670 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24B-000125-0x; Wed, 02 Nov 2022 00:57:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435392.688670; Wed, 02 Nov 2022 00:57:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24A-00011x-Ua; Wed, 02 Nov 2022 00:57:14 +0000
Received: by outflank-mailman (input) for mailman id 435392;
 Wed, 02 Nov 2022 00:57:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq249-00011b-Cb
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq249-0003zW-Bz
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq249-0001GP-BD
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=P7FPN2sgrm1vQYwmaga/3/vpUAyWWxw0qPvqTXjcWVg=; b=FgYWF8fEEDBTb5zsGsQ0ghdHqX
	cz7ynP4fXow2SjE9efqsIT5qn0utNT/masenGkjwjRLcWcS11xh9J6Zww34UVpuSxPt8Tcep4w5bQ
	2O2CajJ931JpC2FfCRjuNX41Xx/QmGOYC00DMG33FUozs3nVRBD8e9iX5hpFMrJxfUt8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: add memory accounting for responses
Message-Id: <E1oq249-0001GP-BD@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:57:13 +0000

commit 0113aacb3d791600668cd7703f6f12ed94fc6d03
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    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 f6d00133643a524d2138c9e3f192bbde719050ba)
---
 tools/xenstore/xenstored_core.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index eeb0d893e8..2e02b577c9 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -260,6 +260,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -904,11 +906,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -973,6 +978,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
@@ -2940,6 +2950,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 	 */
 	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
 		domain_outstanding_inc(conn);
+	/*
+	 * We are restoring the state after Live-Update and the new quota may
+	 * be smaller. So ignore it. The limit will be applied for any resource
+	 * after the state has been fully restored.
+	 */
+	domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:57:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:57:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435393.688674 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24L-00014f-2V; Wed, 02 Nov 2022 00:57:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435393.688674; Wed, 02 Nov 2022 00:57:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24K-00014X-W4; Wed, 02 Nov 2022 00:57:24 +0000
Received: by outflank-mailman (input) for mailman id 435393;
 Wed, 02 Nov 2022 00:57:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24J-00014P-FS
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:23 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24J-0003zd-Ep
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:23 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24J-0001Go-EH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:23 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8seXEgrf7b0KVn5DUeYWFZdD1BuVlgAwP3s30HYL/tc=; b=QwNF1buB50BXEtzhvDIMU9+0P+
	FySYzjfV93BAxRqzGGr0Wb33kp7dWOkV8wf+2RPW6LvQzruopgFRUYjxZ7iSZBFun+wwR/mVwQEO6
	vLv2ZxUkksXkB4yJ8OkHyaIxOMDOymijtzoYfCtBqWwLLIkX1kUZr58nnFxXvkyEp0Eg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: add memory accounting for watches
Message-Id: <E1oq24J-0001Go-EH@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:57:23 +0000

commit 9c2e71fe0611da9ed2ebbf2362a9bb05d42bf0c3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    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 7f9978a2cc37aaffab2fb09593bc598c0712a69b)
---
 tools/xenstore/xenstored_core.c  |  1 +
 tools/xenstore/xenstored_watch.c | 13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2e02b577c9..b1a4575929 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -457,6 +457,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 1d664e3d6b..0d5858df5b 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -211,7 +211,7 @@ static int check_watch_path(struct connection *conn, const void *ctx,
 }
 
 static struct watch *add_watch(struct connection *conn, char *path, char *token,
-			       bool relative)
+			       bool relative, bool no_quota_check)
 {
 	struct watch *watch;
 
@@ -222,6 +222,9 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	watch->token = talloc_strdup(watch, token);
 	if (!watch->node || !watch->token)
 		goto nomem;
+	if (domain_memory_add(conn->id, strlen(path) + strlen(token),
+			      no_quota_check))
+		goto nomem;
 
 	if (relative)
 		watch->relative_path = get_implicit_path(conn);
@@ -265,7 +268,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (domain_watch(conn) > quota_nb_watch_per_domain)
 		return E2BIG;
 
-	watch = add_watch(conn, vec[0], vec[1], relative);
+	watch = add_watch(conn, vec[0], vec[1], relative, false);
 	if (!watch)
 		return errno;
 
@@ -296,6 +299,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -311,6 +316,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
@@ -373,7 +380,7 @@ void read_state_watch(const void *ctx, const void *state)
 	if (!path)
 		barf("allocation error for read watch");
 
-	if (!add_watch(conn, path, token, relative))
+	if (!add_watch(conn, path, token, relative, true))
 		barf("error adding watch");
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:57:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:57:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435394.688679 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24V-00017W-4R; Wed, 02 Nov 2022 00:57:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435394.688679; Wed, 02 Nov 2022 00:57:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24V-00017K-1P; Wed, 02 Nov 2022 00:57:35 +0000
Received: by outflank-mailman (input) for mailman id 435394;
 Wed, 02 Nov 2022 00:57:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24T-000176-Iw
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24T-0003zm-IC
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:33 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24T-0001HD-HJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:33 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=BgMEKjE1zvCiMsTWVAa1G71bamMhBA3L0bSjZn6CV0E=; b=cQIHyvnnt51DP71+Md8QKKaUXC
	2hcPi3pxTCCqSO2k0ny+O3nH0CvYkjJGoND7NBaz/314GlS9jSN0Pa+UufGvvKCcNDI3lya0b3RK9
	5rqbXgZ/NYkOpSeUYHzbaW6uvEpDebfOlvzS7CHXlNJAGpUD+eHVvLVow2+5aJdU3Qjk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: add memory accounting for nodes
Message-Id: <E1oq24T-0001HD-HJ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:57:33 +0000

commit 32efe29a00efab2896cc973e966a35ecad556495
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    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 b1a4575929..f27d5c0101 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 2fb37dbfe8..5c1b574bff 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 7bd41eb475..ace9a11d77 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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:57:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:57:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435395.688682 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24f-0001Ah-7K; Wed, 02 Nov 2022 00:57:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435395.688682; Wed, 02 Nov 2022 00:57:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24f-0001AZ-4K; Wed, 02 Nov 2022 00:57:45 +0000
Received: by outflank-mailman (input) for mailman id 435395;
 Wed, 02 Nov 2022 00:57:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24d-0001AF-Lq
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24d-000409-LA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24d-0001Hc-KR
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=TiXlZKv7JIGTcJ+47TCMkJL6RfI+IbH1tkjy+sJiUUU=; b=h9ZzeR9iLCfGikFzdd3aYj6w1W
	bsMGBA7Kdfeh88HWfUScfzHBR9r+ut9B6a/tDIBO2AETETz+xagssFGbsymuyZMvOIgRzbHxxaCC1
	it3EM8oYOktpmIzH4BkX3Isd+GOEnyIILRsxN8j858MY2F3aVgD4uIq8xj11FJKMjAx4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: add exports for quota variables
Message-Id: <E1oq24d-0001Hc-KR@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:57:43 +0000

commit 1fc3ecc9bfead0a50d8e05de983ed2a8f02fa03c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 1da16d5990b5f7752657fca3e948f735177ea9ad)
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 5c1b574bff..1eb3708f82 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -268,6 +268,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ace9a11d77..28774813de 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static struct accessed_node *find_accessed_node(struct transaction *trans,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 0d5858df5b..4970e9f1a1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:57:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:57:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435396.688686 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24p-0001Dh-8f; Wed, 02 Nov 2022 00:57:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435396.688686; Wed, 02 Nov 2022 00:57:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24p-0001DZ-5q; Wed, 02 Nov 2022 00:57:55 +0000
Received: by outflank-mailman (input) for mailman id 435396;
 Wed, 02 Nov 2022 00:57:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24n-0001DM-Os
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24n-00040D-OD
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24n-0001I1-NQ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:57:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=DWhRKKooYnEztu4yHH1fBaFa5WbLHosRi4rjbKOkYwg=; b=34YAGpIUBmReJIKDANJBA4XmGr
	LYZTppkHldyNghMnR+jiJ7MdNXRSOjce1XQonMaUqi1hvOZJ9Rkaftk8cPoAQAZhaX/YbiqRhH8MW
	h1HlRN4FDT0M2iU7NiqMF6BTyOU33dMOcfZeVSHM2mlfJj2odqm4hiqUmpnyotYLz1lQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1oq24n-0001I1-NQ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:57:53 +0000

commit 4d30175fdadb75c55acb8abb186727eda7cd5585
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 334dc8b6fd..a7d006519a 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -366,6 +366,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 211fe1fd9b..980279fa53 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -148,6 +148,115 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "path-max", &quota_max_path_len, "Max. length of a node path" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 #ifdef __MINIOS__
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
@@ -777,6 +886,8 @@ static struct cmd_s cmds[] = {
 	{ "memreport", do_control_memreport, "[<file>]" },
 #endif
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index ec542df6a6..3d51425813 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -351,6 +352,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 571aa46d15..0f883936f4 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -91,6 +91,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:58:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:58:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435397.688690 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24z-0001Gl-AJ; Wed, 02 Nov 2022 00:58:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435397.688690; Wed, 02 Nov 2022 00:58:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq24z-0001Gd-7P; Wed, 02 Nov 2022 00:58:05 +0000
Received: by outflank-mailman (input) for mailman id 435397;
 Wed, 02 Nov 2022 00:58:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24x-0001GT-Rx
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24x-00040U-RC
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq24x-0001Ik-QT
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ogvZFAxjB7AHrGBIBi+6b8EEpLKjx/IDdq7Q7I7z3Fs=; b=otVxHeW6CnKi++GQf6CEqSrtEd
	laxexatw9HYRVAE1WzCdUmOco4my95iWhbMrZIfoRJ/xiZcJ+9iEPGwyC8UbZz6NWmKBXkehFnzLh
	ukbe3X+F1h3nANoQa42gksCy/Pjluv3HhSE7f7K9/qfD4aC7mozE7WXg6iGycSuewcss=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1oq24x-0001Ik-QT@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:58:03 +0000

commit 8fabb963e662a544a397cb2afefb2b15af07ace9
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 84734955d4bf629ba459a74773afcde50a52236f)
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ebe18b8e31..6b06f80859 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -21,9 +21,9 @@ let xs_daemon_socket = Paths.xen_run_stored ^ "/socket"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:58:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:58:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435398.688694 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq259-0001JO-Bj; Wed, 02 Nov 2022 00:58:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435398.688694; Wed, 02 Nov 2022 00:58:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq259-0001JG-8x; Wed, 02 Nov 2022 00:58:15 +0000
Received: by outflank-mailman (input) for mailman id 435398;
 Wed, 02 Nov 2022 00:58:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq257-0001J9-Ug
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq257-00040Y-U3
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq257-0001J9-TS
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=on+TwRQUQcmCBkIaAhJ8SSLonK7OMItU577nzGqD6s8=; b=YznMu1n1rhA+cVzOuRQUTVUeC9
	Xb7w3Irvz5x5gATExb5l4snRpupznVpsmVjugL8mP0LacVCeBUVrrvLnkFPOdMyUcIIdFfVCIlqd7
	45wvtdFuqFeyL+opsdXSWKKNHF8FLlesZP7kNe6T168+oMguLilsFJOrrKYFCNZcT+KM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1oq257-0001J9-TS@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:58:13 +0000

commit 45816222bb3da04f4cd3388efc46d127d48b8906
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    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 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff)
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 27790d4a5c..dd58e6979c 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -389,6 +389,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"
@@ -681,9 +682,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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:58:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:58:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435399.688698 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25J-0001MN-D8; Wed, 02 Nov 2022 00:58:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435399.688698; Wed, 02 Nov 2022 00:58:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25J-0001MG-AU; Wed, 02 Nov 2022 00:58:25 +0000
Received: by outflank-mailman (input) for mailman id 435399;
 Wed, 02 Nov 2022 00:58:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25I-0001M5-1K
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25I-00040d-0d
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25I-0001JY-01
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=PsSs18QVyDaPbqB3sLQ9wiy6/SEcHwy/zBlGVSn64bg=; b=I0rxDl8MOR5jwFaGCz4A3zi0PX
	6jbU6yepQLroOY4S3RUPo71C21cyGkFMPpCrZKp/ARgy/CEvPctqsN1U72EO31F0hVXtgseO7jIK+
	orSsWiQbvwSKBgJwzRCOcM1AqBooqqUw6k/NaL2xMqPKpGndYKxqsVBk+PU3DzjNw7og=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml: GC parameter tuning
Message-Id: <E1oq25I-0001JY-01@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:58:24 +0000

commit 9f89883fabd53cb7873cc31778887ba2a1228dd8
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 4a8bacff20b857ca0d628ef5525877ade11f2a42)
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 6b06f80859..ba63a8147e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index d44ae673c4..3b57ad016d 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -104,6 +104,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -265,6 +266,67 @@ let to_file store cons fds file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -274,6 +336,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:58:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:58:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435400.688702 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25T-0001Q7-GD; Wed, 02 Nov 2022 00:58:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435400.688702; Wed, 02 Nov 2022 00:58:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25T-0001Pz-DH; Wed, 02 Nov 2022 00:58:35 +0000
Received: by outflank-mailman (input) for mailman id 435400;
 Wed, 02 Nov 2022 00:58:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25S-0001Pm-4G
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25S-00040h-3d
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25S-0001K1-2v
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=2NhTo0hWgevcl/VRjXAdUHjr+EX+Ptp127IQiDxdLuk=; b=QLWqLxcfyR4dc1iWYRDKVVzOEj
	z4PYs5fzOoQTe1DFBdlsiS3Gwqy3fdKP9VuATA80L1imfU5TVpoddF/tMGx1R/poGkCYPoTUleKAN
	DwBNsDUu6YKHxRXjZq4acLUfSsizUpTkR36YRbWSQ9/Off3SebiNJropmcF20DPbpB50=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml/libs/xb: hide type of Xb.t
Message-Id: <E1oq25S-0001K1-2v@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:58:34 +0000

commit bbb4ceab25124646fa845855f3cb95ae15d0c3f2
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Fri Jul 29 18:53:29 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml/libs/xb: hide type of Xb.t
    
    Hiding the type will make it easier to change the implementation
    in the future without breaking code that relies on it.
    
    No functional change.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba)
---
 tools/ocaml/libs/xb/xb.ml           | 3 +++
 tools/ocaml/libs/xb/xb.mli          | 9 ++-------
 tools/ocaml/xenstored/connection.ml | 8 ++------
 3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 104d319d77..8404ddd8a6 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out
 let input_len con = Queue.length con.pkt_in
 let has_in_packet con = Queue.length con.pkt_in > 0
 let get_in_packet con = Queue.pop con.pkt_in
+let has_partial_input con = match con.partial_in with
+	| HaveHdr _ -> true
+	| NoHdr (n, _) -> n < Partial.header_size ()
 let has_more_input con =
 	match con.backend with
 	| Fd _         -> false
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 3a00da6cdd..794e35bb34 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,13 +66,7 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
-type t = {
-  backend : backend;
-  pkt_in : Packet.t Queue.t;
-  pkt_out : Packet.t Queue.t;
-  mutable partial_in : partial_buf;
-  mutable partial_out : string;
-}
+type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
 val queue : t -> Packet.t -> unit
@@ -97,6 +91,7 @@ val has_output : t -> bool
 val peek_output : t -> Packet.t
 val input_len : t -> int
 val has_in_packet : t -> bool
+val has_partial_input : t -> bool
 val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 65f99ea6f2..38b47363a1 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -125,9 +125,7 @@ let get_perm con =
 let set_target con target_domid =
 	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
 
-let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with
-	| Xenbus.Xb.Xenmmap _ -> true
-	| _ -> false
+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
 let send_reply con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
@@ -280,9 +278,7 @@ let get_transaction con tid =
 
 let do_input con = Xenbus.Xb.input con.xb
 let has_input con = Xenbus.Xb.has_in_packet con.xb
-let has_partial_input con = match con.xb.Xenbus.Xb.partial_in with
-	| HaveHdr _ -> true
-	| NoHdr (n, _) -> n < Xenbus.Partial.header_size ()
+let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:58:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:58:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435402.688706 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25d-0001Sp-HV; Wed, 02 Nov 2022 00:58:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435402.688706; Wed, 02 Nov 2022 00:58:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25d-0001Sh-Ek; Wed, 02 Nov 2022 00:58:45 +0000
Received: by outflank-mailman (input) for mailman id 435402;
 Wed, 02 Nov 2022 00:58:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25c-0001SZ-7Z
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25c-000419-6r
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25c-0001KQ-5z
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=DxP9tzxBOfn8EpbZyf89s6w95sEjiK6D5DjbdSAJ1j0=; b=OImaPTegskKkC+20siNlEfS06t
	nkA232/b+6cYanGbOq+ZAdH2Xkr0f39mfx7ZP0MJEybvwxsSJnWrkmnUPwYw8C1sGGoky7bjl8JSc
	IYRatmLmgiqc8TFmETnOlvBVpaH1Mgu7zAXPRXkwW+hcOOTgzDq5yvxr8q2t76SWLwmc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1oq25c-0001KQ-5z@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:58:44 +0000

commit fccdca83a4425b0e30ec9e29e9a5909e1a55b80d
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c0a86a462721008eca5ff733660de094d3c34bc7)
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  4 +---
 tools/ocaml/xenstored/process.ml    | 15 +++++++--------
 5 files changed, 20 insertions(+), 42 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 38b47363a1..cc20e047d2 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,9 +277,7 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
@@ -307,7 +305,7 @@ let is_bad con = match con.dom with None -> false | Some dom -> Domain.is_bad_do
    Restrictions below can be relaxed once xenstored learns to dump more
    of its live state in a safe way *)
 let has_extra_connection_data con =
-	let has_in = has_input con || has_partial_input con in
+	let has_in = has_partial_input con in
 	let has_out = has_output con in
 	let has_socket = con.dom = None in
 	let has_nondefault_perms = make_perm con.dom <> con.perm in
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index dd58e6979c..cbf7082137 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -195,10 +195,9 @@ let parse_live_update args =
 			| _ when Unix.gettimeofday () < t.deadline -> false
 			| l ->
 				warn "timeout reached: have to wait, migrate or shutdown %d domains:" (List.length l);
-				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, in: %b, out: %b, perm: %s"
+				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, out: %b, perm: %s"
 					(Connection.get_domstr con)
 					(Connection.number_of_transactions con)
-					(Connection.has_input con)
 					(Connection.has_output con)
 					(Connection.get_perm con |> Perms.Connection.to_string)
 					) l in
@@ -706,16 +705,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -725,8 +725,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:58:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:58:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435403.688710 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25n-0001VL-JG; Wed, 02 Nov 2022 00:58:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435403.688710; Wed, 02 Nov 2022 00:58:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25n-0001VE-GF; Wed, 02 Nov 2022 00:58:55 +0000
Received: by outflank-mailman (input) for mailman id 435403;
 Wed, 02 Nov 2022 00:58:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25m-0001V2-AO
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25m-00041D-9i
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25m-0001MO-97
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:58:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=uoHt8Iji29nSEx2E4H3cTUbcMfcL1RsE3PlPH4ttsdE=; b=NcIdhVyvrN9140wOcmAu8F3laZ
	pQK34VQAkH9y/ttILjIJjEc2dkgFQBA94DSEJX4q3+EAC1o/6/0A5mviiSomYgMyJHN73mHpJuey8
	iFBdLVYUh03JVA8Xuy2ovrwYkECoWA8MhhjlSrt+CMriqflVMVgO/4wmJxAUPe6RaiZY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1oq25m-0001MO-97@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:58:54 +0000

commit 9e5290daf923e84ca56a6f3d9fc6a333175ef0f9
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 19171fb5d888b4467a7073e8febc5e05540956e9)
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:59:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:59:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435404.688714 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25x-0001YY-L9; Wed, 02 Nov 2022 00:59:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435404.688714; Wed, 02 Nov 2022 00:59:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq25x-0001YQ-I2; Wed, 02 Nov 2022 00:59:05 +0000
Received: by outflank-mailman (input) for mailman id 435404;
 Wed, 02 Nov 2022 00:59:04 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25w-0001YH-Da
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:04 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25w-00041d-Cm
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq25w-0001My-CB
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=4nFr4TxAy9It7yaSHPabTu23GB+9rS+//jo9sld+fCo=; b=sDMx3NxZ++I2gytHcR2gFrmY8M
	UAX8Sp1pnLC+Rnd2iHEswhutTpgoipWaJUgTSuSLjNOzmuNn1y9KvdyZCyXjcFZayOTgwG8P3QDxp
	51rE/4/b7c3g/UaIsfD3eoiHgyoSyAYkUAPZ9nEWiealuTqsx/KJsBjdTby/Bjt2VH38=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1oq25w-0001My-CB@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:59:04 +0000

commit 64048b4c218099b6adcf46cd7b4d1dc9c658009e
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96)
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index cc20e047d2..9624a5f9da 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -280,6 +408,7 @@ let do_input con = Xenbus.Xb.input con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -323,7 +452,7 @@ let prevents_live_update con = not (is_bad con)
 	&& (has_extra_connection_data con || has_transaction_data con)
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 3c7429fe7f..7d68c583b4 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: Connection.watch list Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -197,6 +216,16 @@ let debug cons =
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
 
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
+
 let filter ~f cons =
 	let fold _ v acc = if f v then v :: acc else acc in
 	[]
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ba63a8147e..327b6d795e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -24,6 +24,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index cbf7082137..ce39ce28b5 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -57,7 +57,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -67,8 +67,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -234,6 +235,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -342,7 +357,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -501,7 +516,7 @@ let do_watch con t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -532,7 +547,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -700,7 +715,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -728,6 +744,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 3b57ad016d..c799e20f11 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:59:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:59:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435405.688718 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq267-0001c9-O5; Wed, 02 Nov 2022 00:59:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435405.688718; Wed, 02 Nov 2022 00:59:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq267-0001c1-LV; Wed, 02 Nov 2022 00:59:15 +0000
Received: by outflank-mailman (input) for mailman id 435405;
 Wed, 02 Nov 2022 00:59:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq266-0001bq-Gc
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:14 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq266-00041h-Fy
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:14 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq266-0001Nv-FD
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:14 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=OEPsqmBqim2hAiKKPCIppCkOlQQ3mMDFQRlETVKvLm4=; b=d6ElJtyt67DD25e4Czu08wzT4h
	hR2xXqJXwoVIAy3yltJX2mZJwtljrx2INPNrZzRm9nIiNYhFmPlGVV/ODWV47WWipHC71r3nQHbiA
	c0aibBECF2RNZIGKGCUXdBNhndPLYdpCSBvItFMpiyh+WNRlnkDHq/UUdJ9zkG1gIorw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1oq266-0001Nv-FD@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:59:14 +0000

commit 26faa6b55881445c25e7e83613c2354090fdff18
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c7bc20d8d123851a468402bbfc9e3330efff21ec)
---
 SUPPORT.md | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index 0fb262f81f..48fb462221 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -179,13 +179,18 @@ Support for running qemu-xen device model in a linux stubdomain.
 
     Status: Tech Preview
 
-## Liveupdate of C xenstored daemon
+## Xenstore
 
-    Status: Tech Preview
+### C xenstored daemon
 
-## Liveupdate of OCaml xenstored daemon
+    Status: Supported
+    Status, Liveupdate: Tech Preview
 
-    Status: Tech Preview
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+    Status, Liveupdate: Not functional
 
 ## Toolstack/3rd party
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:59:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:59:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435406.688722 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26H-0001es-Qb; Wed, 02 Nov 2022 00:59:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435406.688722; Wed, 02 Nov 2022 00:59:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26H-0001ek-NC; Wed, 02 Nov 2022 00:59:25 +0000
Received: by outflank-mailman (input) for mailman id 435406;
 Wed, 02 Nov 2022 00:59:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26G-0001ed-Jt
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26G-00041m-JA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26G-0001OM-IZ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=YXeRYUqsYP6jrYmKJtByDR6gY4ykF+9aTnF1SKINeY4=; b=jLnTi6EAV3pdAH2YPNYLsMwmMS
	0ioKggvP1YkYgXDL573mCjmneVzz1yeAOz1yVDdtZwa9QZTOMWRjgDr/Fim/tSDZfBvSwlYTTIKqv
	kYYFVKIJpy80F1p/kQLnPh9npNB0xZX+vXoS+269jk8Az6U694WbeICOxMk7jdeEAKso=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1oq26G-0001OM-IZ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:59:24 +0000

commit 607e186fe094f8d1c78572cd3b1f7a43730203c1
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2a587de219cc0765330fbf9fac6827bfaf29e29b)
---
 tools/xenstore/xenstored_control.c     | 31 +++++++-------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 29 +++++++------
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 118 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 980279fa53..95a60bf578 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -107,7 +107,7 @@ static const char *lu_begin(struct connection *conn)
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 	/*
 	 * max_pars can be used to limit the size of the parameter vector,
@@ -119,7 +119,7 @@ struct cmd_s {
 	unsigned int max_pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -131,7 +131,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -233,7 +233,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -245,7 +245,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -258,7 +258,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 }
 
 #ifdef __MINIOS__
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	if (num)
@@ -270,7 +270,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 #else
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -285,7 +285,7 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -325,7 +325,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -802,7 +802,7 @@ static const char *lu_start(const void *ctx, struct connection *conn,
 	return NULL;
 }
 
-static int do_control_lu(void *ctx, struct connection *conn,
+static int do_control_lu(const void *ctx, struct connection *conn,
 			 char **vec, int num)
 {
 	const char *ret = NULL;
@@ -852,7 +852,7 @@ static int do_control_lu(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -891,7 +891,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd, len = 0;
@@ -927,7 +927,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	unsigned int cmd, num, off;
 	char **vec = NULL;
@@ -947,11 +948,11 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (cmds[cmd].max_pars)
 		num = min(num, cmds[cmd].max_pars);
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) < num)
 		return EIO;
 
-	return cmds[cmd].func(in, conn, vec + 1, num - 1);
+	return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index aac61f0590..6430c37693 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,5 +16,6 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 void lu_read_state(void);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f27d5c0101..806f24bbab 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1214,11 +1214,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1227,7 +1229,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1239,7 +1241,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1266,7 +1269,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1282,11 +1285,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1476,7 +1481,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1490,12 +1496,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1506,18 +1512,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1527,10 +1534,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 			return errno;
 		if (!name)
 			return ENOMEM;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1628,24 +1635,25 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
 			if (!name)
 				return ENOMEM;
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1660,7 +1668,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1670,13 +1678,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1689,7 +1699,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1706,7 +1717,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1721,7 +1732,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1756,7 +1767,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1764,7 +1775,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1840,6 +1852,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	if ((unsigned int)type >= XS_TYPE_COUNT || !wire_funcs[type].func) {
 		eprintf("Client unknown operation %i", type);
@@ -1860,10 +1873,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3d51425813..d262f4e9db 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -336,7 +336,7 @@ bool domain_can_write(struct connection *conn)
 	return ((intf->rsp_prod - intf->rsp_cons) != XENSTORE_RING_SIZE);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -540,7 +540,8 @@ static struct domain *introduce_domain(const void *ctx,
 }
 
 /* domid, gfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -558,7 +559,7 @@ int do_introduce(struct connection *conn, struct buffered_data *in)
 	if (port <= 0)
 		return EINVAL;
 
-	domain = introduce_domain(in, domid, port, false);
+	domain = introduce_domain(ctx, domid, port, false);
 	if (!domain)
 		return errno;
 
@@ -581,7 +582,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -625,7 +627,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -640,7 +643,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -655,7 +659,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -663,18 +668,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -695,7 +699,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 0f883936f4..da513443cd 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -24,25 +24,32 @@ void handle_event(void);
 void check_domains(bool restore);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(int evtfd);
 void dom0_init(void);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 28774813de..3e3eb47326 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -481,7 +481,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -494,8 +495,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -544,7 +545,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -562,8 +564,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	if (!conn->transaction_started)
 		conn->ta_start_time = 0;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 4970e9f1a1..854bbcad6e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -243,7 +243,7 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	return NULL;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -252,7 +252,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	errno = check_watch_path(conn, in, &(vec[0]), &relative);
+	errno = check_watch_path(conn, ctx, &(vec[0]), &relative);
 	if (errno)
 		return errno;
 
@@ -283,7 +283,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -291,7 +292,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 0e693f0839..091890edca 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:59:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:59:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435407.688726 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26R-0001iI-Tr; Wed, 02 Nov 2022 00:59:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435407.688726; Wed, 02 Nov 2022 00:59:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26R-0001iA-Qo; Wed, 02 Nov 2022 00:59:35 +0000
Received: by outflank-mailman (input) for mailman id 435407;
 Wed, 02 Nov 2022 00:59:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26Q-0001i2-N1
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26Q-00041q-MK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26Q-0001Ol-Lm
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9VhrHzc245Vd7BFmFbleqVkN736akrTpH+llmbg9KVk=; b=XFEOVlVk8y4JothPL12MyGs/GI
	8o1oa+GvcPK8orE6rm1O6lUSY/xSgvcSMIMArcwgcjRLAmUjlolcfhSpQDlj3w1S3ElNonJVkb+wt
	mHh/0GuoIPSEpLs3iaYaRaaYmu8O2ghpSdeddY7lXkKQdwO9Ojsd14Y0IRPFS7D/B+HM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: fix checking node permissions
Message-Id: <E1oq26Q-0001Ol-Lm@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:59:34 +0000

commit 8012324cb9e676bd342a5adfda1700525f195e2e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ab128218225d3542596ca3a02aee80d55494bef8)
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 806f24bbab..8aecd425f2 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1723,6 +1723,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index d262f4e9db..8b503c2dfe 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -881,7 +881,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -889,20 +888,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -915,8 +932,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -933,8 +948,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index da513443cd..0b4f56b814 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -66,6 +66,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:59:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:59:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435408.688730 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26c-0001lK-VA; Wed, 02 Nov 2022 00:59:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435408.688730; Wed, 02 Nov 2022 00:59:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26c-0001lA-SM; Wed, 02 Nov 2022 00:59:46 +0000
Received: by outflank-mailman (input) for mailman id 435408;
 Wed, 02 Nov 2022 00:59:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26a-0001kr-Pv
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26a-00042K-PE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26a-0001PA-Oe
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=dh1Xs3hjyYAQT5PPpXUnLq6rqFziAn0+RxDwN/pJRu0=; b=gHpAFFqnDMun6zdoTHbNQ/4MGB
	k7qVMppsrA6u3FR+1JT3ZL9BwS34YuDhh7YPUOxAxsWV3aMgO3M2Z0kJWzpk3BbRlxMjwiqZeRnq6
	f7HTSROP1fsjT2Lxt4GudVaeB47Ls4TUIiVfKx1/3FyhSeXHg+aWeqBZES/2oqwuqe+E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1oq26a-0001PA-Oe@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:59:44 +0000

commit 62755d0a90344e704062e7b6943a3fa2dc5e02e6
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 86 ++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 31 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8aecd425f2..46a37e5257 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1343,45 +1343,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name)
 static struct node *construct_node(struct connection *conn, const void *ctx,
 				   const char *name)
 {
-	struct node *parent, *node;
-	char *parentname = get_parent(ctx, name);
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
 
 	if (!parentname)
 		return NULL;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
 
-	/* Add child to parent. */
-	if (add_child(ctx, parent, name))
-		goto nomem;
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
 
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
 
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 00:59:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 00:59:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435409.688733 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26n-0001oJ-0D; Wed, 02 Nov 2022 00:59:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435409.688733; Wed, 02 Nov 2022 00:59:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26m-0001oC-Tx; Wed, 02 Nov 2022 00:59:56 +0000
Received: by outflank-mailman (input) for mailman id 435409;
 Wed, 02 Nov 2022 00:59:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26k-0001nz-Sp
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26k-00042O-SB
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26k-0001PZ-RY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 00:59:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Tx9ojA9HcazvT0Pjipr0vKeJ27mHnWWeaezPPDFJXQk=; b=vpZqKq5MTrmv9CB6MxyDDi1vND
	m2EbrPxrQ0xzBw5+m7RHpPIiu/qX2icN4C489GPtgEdrJ2q/+EaK1MzEml6yN0eicDglEGNaByCJl
	Uyq1WGUWesUTZQN0nmkh9ur+98Ogphjebz7xJqLerx2lz2++KoT/ot0+a5TffoJ/EdZ4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1oq26k-0001PZ-RY@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 00:59:54 +0000

commit b9a005b0b4520261c6c362fca55500782837f119
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4)
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 46a37e5257..4c3897721b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1574,15 +1574,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1592,7 +1592,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2226,6 +2228,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2278,12 +2291,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2300,11 +2308,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:00:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:00:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435410.688738 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26w-00047Y-2E; Wed, 02 Nov 2022 01:00:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435410.688738; Wed, 02 Nov 2022 01:00:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq26v-00046h-VV; Wed, 02 Nov 2022 01:00:05 +0000
Received: by outflank-mailman (input) for mailman id 435410;
 Wed, 02 Nov 2022 01:00:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26v-0003gP-5g
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26u-0005SL-VK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq26u-0001Qr-Ui
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=fDzeDbEksLrlzjicKwlteeR0buIXweUwjIF6zVzv81U=; b=4fnwQ+xLAy6D7dog3lM/8OhJ+q
	TSSafXOCrMvP4LjHWwC4RjR2FnYmwzxxOC6Pa6QVY0rv6I4h1x9jBryBvVuebXsh5i+fKyygW6SmQ
	QyLLfW/nMXo9Dch5PCmExAwL3ZWG7pcA+/eIH/VDd5aBURaVGRxRMgDzW68aNIGuy6BY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: add generic treewalk function
Message-Id: <E1oq26u-0001Qr-Ui@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:00:04 +0000

commit 83b6c511a5989a83c50daae83c5b5a683d6dc096
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d7c5d19bc27492360196e7dad2b227908564fff)
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 4c3897721b..7463d0a002 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1804,6 +1804,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2206,18 +2335,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2277,7 +2394,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1eb3708f82..f0fd8c3528 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -195,6 +195,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -334,6 +335,45 @@ void read_state_buffered_data(const void *ctx, struct connection *conn,
 			      const struct xs_state_connection *sc);
 void read_state_node(const void *ctx, const void *state);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:00:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:00:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435411.688742 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq276-0007h9-3q; Wed, 02 Nov 2022 01:00:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435411.688742; Wed, 02 Nov 2022 01:00:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq276-0007gh-0t; Wed, 02 Nov 2022 01:00:16 +0000
Received: by outflank-mailman (input) for mailman id 435411;
 Wed, 02 Nov 2022 01:00:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq275-0007N7-2o
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq275-0001LZ-2C
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq275-0001Ry-1U
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=h+S+hkyje017tZ5vzbjX4NKLgdKW4suLaYpRp99cpOI=; b=uqK6GhWLUV/Uki14FOgaO2znl8
	S7iplpS8TwWC32ImoQB/JRuX3UaFwEqf9eFGNDbyhPQpb98hbaGc3KOVMR9FqMqVkvFonXRkSk2cf
	uH/OQsxNU26T22oZWpSFjf9mY3Ufrt34CPTmO/xEYGhY3RUe94gAJcCbkZN2la4T3E1w=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: simplify check_store()
Message-Id: <E1oq275-0001Ry-1U@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:00:15 +0000

commit 4096512a70fd0bb65e40ed4269a1ca74dbb16220
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 70f719f52a220bc5bc987e4dd28e14a7039a176b)
---
 tools/xenstore/xenstored_core.c | 47 +++++++++++++----------------------------
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 7463d0a002..a48255c64c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2378,50 +2378,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-		if (!children) {
-			log("check_store create table: ENOMEM");
-			return ENOMEM;
-		}
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2431,19 +2415,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:00:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:00:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435413.688746 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27G-00031X-6T; Wed, 02 Nov 2022 01:00:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435413.688746; Wed, 02 Nov 2022 01:00:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27G-00030p-3e; Wed, 02 Nov 2022 01:00:26 +0000
Received: by outflank-mailman (input) for mailman id 435413;
 Wed, 02 Nov 2022 01:00:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27F-0002ga-7b
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27F-0005cN-5K
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27F-0001SO-4d
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=98xL+a/K/45TYWEpEnijpcqg8PhKleqd1Z3hPG1XfsQ=; b=CMNv62ifdUW5k3QNGO2bolRMfY
	gukFms8GvIKv0iXfydCYsGeVf/P0hbV25y1VXlMW5AH+Z3ZUi2Y24O4mZgQaLKp5D8EjN3y4g3lpk
	279BVzbCfSEPaNH7/JpfRUlA9OpfznSQ2hy5VD53DcIBcqru1fm5JCWvjXepJC+fIDS4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: use treewalk for check_store()
Message-Id: <E1oq27F-0001SO-4d@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:00:25 +0000

commit a95277ee36e1db2f67e8091f4ea401975d341659
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index a48255c64c..ed8bc9b02e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2345,18 +2345,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2370,70 +2358,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
-
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
-
-			childnode = read_node(NULL, childname, childname);
+	struct hashtable *reachable = arg;
 
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2482,24 +2429,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char * root = talloc_strdup(NULL, "/");
-	struct hashtable * reachable =
-		create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
+
+	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
 		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:00:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:00:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435414.688750 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27Q-0006iy-8G; Wed, 02 Nov 2022 01:00:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435414.688750; Wed, 02 Nov 2022 01:00:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27Q-0006iQ-56; Wed, 02 Nov 2022 01:00:36 +0000
Received: by outflank-mailman (input) for mailman id 435414;
 Wed, 02 Nov 2022 01:00:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27P-0006Pq-9I
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27P-0001Y0-8Z
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27P-0001Ss-7e
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=GKOIebflfjxGfIldCK+n4cnwwPw99rg5eMQtMimIexw=; b=jgAuCVIK6FuvgXqqwStk/3T00I
	Bhbj811GfDJ6Ed4BO02KRE6mJv2q8KGLk6ia7kHQEWk1QfCgoMs2TiMQOLPaodX42s0C3LWSXwpbo
	9RuQ/aFwMJTvX6YEU1MPYizaULx5u4TjJdQ04ZmBlivqvv2iKvCocluK4CX6WL4aq6Ks=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1oq27P-0001Ss-7e@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:00:35 +0000

commit 9ead5845034c04a5c6e04d9b069d9c13141f4f33
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ea16962053a6849a6e7cada549ba7f8c586d85c6)
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ed8bc9b02e..9576411757 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1300,21 +1300,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1585,69 +1570,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1655,9 +1630,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1694,7 +1681,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:00:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:00:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435415.688754 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27a-00027m-9b; Wed, 02 Nov 2022 01:00:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435415.688754; Wed, 02 Nov 2022 01:00:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27a-00027K-6c; Wed, 02 Nov 2022 01:00:46 +0000
Received: by outflank-mailman (input) for mailman id 435415;
 Wed, 02 Nov 2022 01:00:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27Z-0001nP-Cj
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27Z-0005kq-C0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27Z-0001TO-B7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=v1LxmalyovV5xGUyQhjuC/Jl9oQR7K1bpy2JOv5PP+4=; b=5qgy2e9i6C+ftawmh0EQsEye+e
	Gus4b4+gEhEyM5eS1tEcFhwZj9ndhyBFv1xy0BVX6xcjDwIlOeXz1XvaE1Qf8am4CCYuvZjRU9+wE
	lo5auTzunvlJ/lK1ZPgZkMDGq9c1rt0JxqpKCOZ1TLk4RF6O0L6lTsPk6QyQkG8VeUSw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: use treewalk for creating node records
Message-Id: <E1oq27Z-0001TO-B7@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:00:45 +0000

commit 84674f206778e9b3d8d67c6c76aa8094a262d5ec
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: use treewalk for creating node records
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when creating the node records during a live update.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 297ac246a5d8ed656b349641288f3402dcc0251e)
---
 tools/xenstore/xenstored_core.c   | 127 ++++++++++++++++----------------------
 tools/xenstore/xenstored_core.h   |   3 +-
 tools/xenstore/xenstored_domain.c |   2 +-
 3 files changed, 54 insertions(+), 78 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9576411757..e8cdfeef50 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2990,132 +2990,109 @@ const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 	return NULL;
 }
 
-const char *dump_state_node_perms(FILE *fp, struct xs_state_node *sn,
-				  const struct xs_permissions *perms,
+const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
 				  unsigned int n_perms)
 {
 	unsigned int p;
 
 	for (p = 0; p < n_perms; p++) {
+		struct xs_state_node_perm sp;
+
 		switch ((int)perms[p].perms & ~XS_PERM_IGNORE) {
 		case XS_PERM_READ:
-			sn->perms[p].access = XS_STATE_NODE_PERM_READ;
+			sp.access = XS_STATE_NODE_PERM_READ;
 			break;
 		case XS_PERM_WRITE:
-			sn->perms[p].access = XS_STATE_NODE_PERM_WRITE;
+			sp.access = XS_STATE_NODE_PERM_WRITE;
 			break;
 		case XS_PERM_READ | XS_PERM_WRITE:
-			sn->perms[p].access = XS_STATE_NODE_PERM_BOTH;
+			sp.access = XS_STATE_NODE_PERM_BOTH;
 			break;
 		default:
-			sn->perms[p].access = XS_STATE_NODE_PERM_NONE;
+			sp.access = XS_STATE_NODE_PERM_NONE;
 			break;
 		}
-		sn->perms[p].flags = (perms[p].perms & XS_PERM_IGNORE)
+		sp.flags = (perms[p].perms & XS_PERM_IGNORE)
 				     ? XS_STATE_NODE_PERM_IGNORE : 0;
-		sn->perms[p].domid = perms[p].id;
-	}
+		sp.domid = perms[p].id;
 
-	if (fwrite(sn->perms, sizeof(*sn->perms), n_perms, fp) != n_perms)
-		return "Dump node permissions error";
+		if (fwrite(&sp, sizeof(sp), 1, fp) != 1)
+			return "Dump node permissions error";
+	}
 
 	return NULL;
 }
 
-static const char *dump_state_node_tree(FILE *fp, char *path)
+struct dump_node_data {
+	FILE *fp;
+	const char *err;
+};
+
+static int dump_state_node_err(struct dump_node_data *data, const char *err)
+{
+	data->err = err;
+	return WALK_TREE_ERROR_STOP;
+}
+
+static int dump_state_node(const void *ctx, struct connection *conn,
+			   struct node *node, void *arg)
 {
-	unsigned int pathlen, childlen, p = 0;
+	struct dump_node_data *data = arg;
+	FILE *fp = data->fp;
+	unsigned int pathlen;
 	struct xs_state_record_header head;
 	struct xs_state_node sn;
-	TDB_DATA key, data;
-	const struct xs_tdb_record_hdr *hdr;
-	const char *child;
 	const char *ret;
 
-	pathlen = strlen(path) + 1;
-
-	set_tdb_key(path, &key);
-	data = tdb_fetch(tdb_ctx, key);
-	if (data.dptr == NULL)
-		return "Error reading node";
-
-	/* Clean up in case of failure. */
-	talloc_steal(path, data.dptr);
-
-	hdr = (void *)data.dptr;
+	pathlen = strlen(node->name) + 1;
 
 	head.type = XS_STATE_TYPE_NODE;
 	head.length = sizeof(sn);
 	sn.conn_id = 0;
 	sn.ta_id = 0;
 	sn.ta_access = 0;
-	sn.perm_n = hdr->num_perms;
+	sn.perm_n = node->perms.num;
 	sn.path_len = pathlen;
-	sn.data_len = hdr->datalen;
-	head.length += hdr->num_perms * sizeof(*sn.perms);
+	sn.data_len = node->datalen;
+	head.length += node->perms.num * sizeof(*sn.perms);
 	head.length += pathlen;
-	head.length += hdr->datalen;
+	head.length += node->datalen;
 	head.length = ROUNDUP(head.length, 3);
 
 	if (fwrite(&head, sizeof(head), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node head error");
 	if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node state error");
 
-	ret = dump_state_node_perms(fp, &sn, hdr->perms, hdr->num_perms);
+	ret = dump_state_node_perms(fp, node->perms.p, node->perms.num);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
 
-	if (fwrite(path, pathlen, 1, fp) != 1)
-		return "Dump node path error";
-	if (hdr->datalen &&
-	    fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1)
-		return "Dump node data error";
+	if (fwrite(node->name, pathlen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node path error");
+
+	if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node data error");
 
 	ret = dump_state_align(fp);
 	if (ret)
-		return ret;
-
-	child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen;
-
-	/*
-	 * Use path for constructing children paths.
-	 * As we don't write out nodes without having written their parent
-	 * already we will never clobber a part of the path we'll need later.
-	 */
-	pathlen--;
-	if (path[pathlen - 1] != '/') {
-		path[pathlen] = '/';
-		pathlen++;
-	}
-	while (p < hdr->childlen) {
-		childlen = strlen(child) + 1;
-		if (pathlen + childlen > XENSTORE_ABS_PATH_MAX)
-			return "Dump node path length error";
-		strcpy(path + pathlen, child);
-		ret = dump_state_node_tree(fp, path);
-		if (ret)
-			return ret;
-		p += childlen;
-		child += childlen;
-	}
-
-	talloc_free(data.dptr);
+		return dump_state_node_err(data, ret);
 
-	return NULL;
+	return WALK_TREE_OK;
 }
 
 const char *dump_state_nodes(FILE *fp, const void *ctx)
 {
-	char *path;
-
-	path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX);
-	if (!path)
-		return "Path buffer allocation error";
+	struct dump_node_data data = {
+		.fp = fp,
+		.err = "Dump node walk error"
+	};
+	struct walk_funcs walkfuncs = { .enter = dump_state_node };
 
-	strcpy(path, "/");
+	if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data))
+		return data.err;
 
-	return dump_state_node_tree(fp, path);
+	return NULL;
 }
 
 void read_state_global(const void *ctx, const void *state)
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index f0fd8c3528..3190494bbe 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -326,8 +326,7 @@ const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 				     const struct connection *conn,
 				     struct xs_state_connection *sc);
 const char *dump_state_nodes(FILE *fp, const void *ctx);
-const char *dump_state_node_perms(FILE *fp, struct xs_state_node *sn,
-				  const struct xs_permissions *perms,
+const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
 				  unsigned int n_perms);
 
 void read_state_global(const void *ctx, const void *state);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8b503c2dfe..a91cc75ab5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -1449,7 +1449,7 @@ static const char *dump_state_special_node(FILE *fp, const char *name,
 	if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
 		return "Dump special node error";
 
-	ret = dump_state_node_perms(fp, &sn, perms->p, perms->num);
+	ret = dump_state_node_perms(fp, perms->p, perms->num);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:00:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:00:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435416.688758 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27k-0006C3-BD; Wed, 02 Nov 2022 01:00:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435416.688758; Wed, 02 Nov 2022 01:00:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27k-0006BQ-88; Wed, 02 Nov 2022 01:00:56 +0000
Received: by outflank-mailman (input) for mailman id 435416;
 Wed, 02 Nov 2022 01:00:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27j-0005tG-Ft
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27j-0001iw-FC
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27j-0001Tx-EX
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:00:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=iRWnotw43zt+OKqIKIbbbnhjDtUo3O3Gm6jaqVQf6ko=; b=299UWnTqYLmHzSseszZXSfFXWP
	ars5dRY19mex1zyfPRZRD381b9tuDKXUxXVMirf4gGyHXYbtMYJn+b+ngVnqstC1OQ/CjqyLXlR9I
	kxBNUs/JfyRjWry4cscDF7pAP45Sm+X6tHfRtHv/BPjFceEc1i5EmcyNb54YWTmfOxXM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1oq27j-0001Tx-EX@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:00:55 +0000

commit da87661d058c4a6cf2ea6439771b9834f1c06223
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 755d3f9debf8879448211fffb018f556136f6a79)
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 84 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 80 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e8cdfeef50..d5b2e59b0d 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -80,6 +80,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -722,7 +723,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -765,7 +766,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1617,7 +1618,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1681,7 +1682,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2537,6 +2538,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2561,6 +2564,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 #ifndef NO_LIVE_UPDATE
@@ -2641,7 +2645,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2677,6 +2681,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 3190494bbe..9a9dbb2c3c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -233,6 +233,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(bool live_update);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 struct connection *get_connection_by_id(unsigned int conn_id);
@@ -279,6 +282,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index a91cc75ab5..ee4b19387d 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -196,10 +196,64 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		set_tdb_key(node->name, &key);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -857,15 +911,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -926,23 +980,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -960,15 +1002,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1087,7 +1129,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 0b4f56b814..491d7a325b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,7 +65,7 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:01:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:01:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435417.688762 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27u-0001ob-Ed; Wed, 02 Nov 2022 01:01:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435417.688762; Wed, 02 Nov 2022 01:01:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq27u-0001o9-Bf; Wed, 02 Nov 2022 01:01:06 +0000
Received: by outflank-mailman (input) for mailman id 435417;
 Wed, 02 Nov 2022 01:01:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27t-0001Wn-Jo
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27t-00065q-J9
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq27t-0001Ug-Hf
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=rZLCr6wE4xpWVou3xGHHdG7gNj09/JF/YyMkvig8QV8=; b=rh4flkaUf35WS42oAU8iijkgpn
	ZAs1WwCXZJ2vz0nHzNXVPN4ltV+IKS81p3Sq+/kZip7CkQwOQztwWfj5gCNBf7Yv/wodcUWEjdz8V
	Q+hz60WtoMj28W6Lwgz0ClyybtLoIhuh8KHDw8jeWv0geFgq30Uyw6j7eazFzgVLiQVk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: make the internal memory data base the default
Message-Id: <E1oq27t-0001Ug-Hf@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:01:05 +0000

commit 4269999ecedf79452a3fbbfab842f045d1ece16e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d174fefa90487ddd25ebc618028f67b2e8a1f795)
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 32689abd74..d080dae5d3 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -214,9 +214,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom->cmdline = xc_dom_strdup(dom, cmdline);
     dom->xenstore_domid = domid;
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index d5b2e59b0d..9ddbd934f7 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2230,7 +2230,7 @@ static void accept_connection(int sock)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2537,7 +2537,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2563,7 +2564,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2645,7 +2646,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2679,7 +2681,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:01:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:01:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435418.688766 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq284-00061X-GI; Wed, 02 Nov 2022 01:01:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435418.688766; Wed, 02 Nov 2022 01:01:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq284-00060v-DP; Wed, 02 Nov 2022 01:01:16 +0000
Received: by outflank-mailman (input) for mailman id 435418;
 Wed, 02 Nov 2022 01:01:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq283-0005jL-Oa
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq283-0001u7-Nr
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq283-0001V7-LN
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=viGDAeKZueASo8P8iLEU2ZabEsRUFhdGxznd+T55w8w=; b=QWyA8w4SRk21ZTR+rXYjapmns6
	k1XYOddYt/bISV/E+9PDp94lUNIuPPDRx1uzBl4EbYF5IKQxGhaVKdyubOBeyCX1YTzLnk4Cd3CPu
	CuWQ+S4NnJ+abkREUpsv+ILesuHO8QO/RBVx21x2q/JWqzlIleoPctdf2JXXuCYFmbwk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] docs: enhance xenstore.txt with permissions description
Message-Id: <E1oq283-0001V7-LN@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:01:15 +0000

commit bc3921135cf8590d0f587f460be431922183c4c4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d084d2c6dff7044956ebdf83a259ad6081a1d921)
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index a7d006519a..eccd596ee3 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:01:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:01:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435419.688770 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq28E-0001WK-HZ; Wed, 02 Nov 2022 01:01:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435419.688770; Wed, 02 Nov 2022 01:01:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq28E-0001Vn-Eu; Wed, 02 Nov 2022 01:01:26 +0000
Received: by outflank-mailman (input) for mailman id 435419;
 Wed, 02 Nov 2022 01:01:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28D-0001GV-TQ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28D-00069O-Qz
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28D-0001VY-QG
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=vYkW53l2Xazxt3sI6L6604YoGJyLKvO2xssf8Nd3ao4=; b=glxtu/U0wWGV2BMcRR//E1PfyC
	fm4TUSn5QtHuQ7S1k6REH1oy63mgiTk/HmxQeSYH9L8SXX7yjvMX6AOu5m0DpST428s5ZoDcAgTGF
	9gaLGrDNTBrEGBcL6Bha18P0txxrins5cgBylHNvAIos3qpY9ZfUdMYtmLbcdWMo3svI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1oq28D-0001VY-QG@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:01:25 +0000

commit b9ede0950b3a6526d5ccea074841f093e0580948
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit db471408edd46af403b8bd44d180a928ad7fbb80)
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 20e67b1427..70f0c83de4 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -87,10 +87,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; SymbolMap.iter (fun _ -> recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid _ node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = SymbolMap.map walk node.children }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			SymbolMap.map walk node.children |> SymbolMap.filter is_valid } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -444,11 +455,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:01:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:01:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435420.688774 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq28O-0005QN-JQ; Wed, 02 Nov 2022 01:01:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435420.688774; Wed, 02 Nov 2022 01:01:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq28O-0005Po-Gf; Wed, 02 Nov 2022 01:01:36 +0000
Received: by outflank-mailman (input) for mailman id 435420;
 Wed, 02 Nov 2022 01:01:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28N-0005Bx-UY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28N-0001zD-Tt
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28N-0001Vx-TJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=LZFdx0vLdNeFZ4J5D01QafPqP/ewkQ41m1j+TRnfS5U=; b=yFQiJXoJm1L4UzPer779FEVIj9
	WC5H4d3I1Azntw42u7ozzzSv7CjrSUc6txRubBBtvWJIBuHy9x8e8yBvFZ5NZ1gIskRjIWsb4wbED
	QU4oefREKOLpjPu9VcFlctE6L9B14ATaXI8ewVvx1tEAVJXHUv+f9f/rjVa85s14Fge8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1oq28N-0001Vx-TJ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:01:35 +0000

commit d3649d33e1eae49d3925ef34a7ccf39cae8852e6
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3)
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index ce39ce28b5..6cb990ee7f 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -722,7 +722,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:01:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:01:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435421.688777 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq28Z-00017i-Kv; Wed, 02 Nov 2022 01:01:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435421.688777; Wed, 02 Nov 2022 01:01:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq28Z-00017E-ID; Wed, 02 Nov 2022 01:01:47 +0000
Received: by outflank-mailman (input) for mailman id 435421;
 Wed, 02 Nov 2022 01:01:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28Y-0000h0-1D
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28Y-0006J5-0W
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28X-0001WS-W3
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=+h5zHGPc+FOpIqqsDOiD/grM6BpCIRqBaeC1TRVUZ50=; b=KEyDrxQRktESiUNX12Tw+TaUlX
	FnT552NWTmyx0LkvdDMzSiQ3qxW/TZ1SJLoBKrNIEchhF/GoXVPe5G6SVdxRxoqx1MSNBgP+49wJM
	O+OLZFLPxuCfwluXACRl7Ad1hfs4Pmf+DNECdVRObgLLAec4EoCxclv+Xy8PFRlfMUBE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: fix deleting node in transaction
Message-Id: <E1oq28X-0001WS-W3@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:01:45 +0000

commit 2d3476effe3a9236867562f14dc26979a6527080
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187)
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 3e3eb47326..7ffe21bb52 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -418,7 +418,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 01:01:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 01:01:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435422.688782 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq28j-0003lz-MT; Wed, 02 Nov 2022 01:01:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435422.688782; Wed, 02 Nov 2022 01:01:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq28j-0003lr-Jn; Wed, 02 Nov 2022 01:01:57 +0000
Received: by outflank-mailman (input) for mailman id 435422;
 Wed, 02 Nov 2022 01:01:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28i-0003lP-4Z
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28i-0001x9-3s
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq28i-0001Wr-30
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 01:01:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ldfOTQ0z8EQa+6A838bsh4Js4Q0iU+j2c8FtW5M2zr8=; b=POc2Y6YH9XRPXeSc+IIWOqyPoR
	Y8D9d/UWAwTvjxmu0pFzhBgiZMZlenV4SjUjO0UGPIzQlBU+Rwi3Xxl4BoDbnv160tobM3nUUjSSm
	wJ7b1FYMfOpE1ecDGMF4Apkgs0AbNnO4uQcM1JvefL7EMlNk0QlYDBwolZ2p3bNTJEYE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1oq28i-0001Wr-30@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 01:01:56 +0000

commit e818f4f0dabf83a6138cd77d7464495fab7bfc16
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:03:25 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff)
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9ddbd934f7..3c008c8cd4 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -692,8 +692,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -811,10 +810,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 7ffe21bb52..ac854197ca 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -199,25 +200,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -240,7 +236,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -259,10 +254,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -273,9 +264,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -302,7 +294,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -321,7 +313,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -333,7 +325,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -371,100 +362,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -556,6 +537,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -579,13 +561,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -660,7 +646,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -672,11 +658,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:44:11 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:44:11 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435497.688843 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7To-0005yw-9I; Wed, 02 Nov 2022 06:44:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435497.688843; Wed, 02 Nov 2022 06:44:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7To-0005yo-5l; Wed, 02 Nov 2022 06:44:04 +0000
Received: by outflank-mailman (input) for mailman id 435497;
 Wed, 02 Nov 2022 06:44:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Tm-0005yi-NH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Tm-0002rh-LW
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Tm-00086W-Jj
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=pS6Igsh3WqEB4F8dbCdcPlKnzxAeGUyE8TBDf0zm74w=; b=j19tsyMXPbHTBLLLmHkCbSWhZk
	ZNNV/lBmCttUU6Ux3muldk1VQhnGFcHnNcwDo7zjZvqK9tUj6pzhuMBYhnyJMy4VAk5We15nfOoKk
	QJlnd1DwAjLqmAXHm7XUZhmNUSzvnAoBKQ/rM6kU+CoifenKR4wIsvKmPYGxDQlrd19k=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1oq7Tm-00086W-Jj@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:44:02 +0000

commit 149ebf0e0228ece2ec704f6ac2ec35f68e94a23f
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 1cd3cc7ea27cda7640a8d895e09617b61c265697)
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 08190ecc55..c952608468 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -975,9 +975,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -988,7 +987,7 @@ static int destroy_node(void *_node)
 
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -997,7 +996,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1019,23 +1019,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:44:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:44:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435498.688846 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Ty-00060c-9m; Wed, 02 Nov 2022 06:44:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435498.688846; Wed, 02 Nov 2022 06:44:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Ty-00060V-7J; Wed, 02 Nov 2022 06:44:14 +0000
Received: by outflank-mailman (input) for mailman id 435498;
 Wed, 02 Nov 2022 06:44:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Tw-00060J-PY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Tw-0002rl-On
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Tw-00087G-Nt
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=tC3CUG5HLW2HJQneGtIi4PMRy4CE2wobfpYjCqR3LDw=; b=tghMH1MASYObR4WSNg/8QH/o6L
	P8VkcZUGtSkVmGEFePCXff1bQ+upsvEG+hvBi6MV7RTEy6vb9thp466/q7Sbsgw9WZgySzvPI/Pj1
	LDcXBiHJ8B/2DCVsoSWuTphMIcsUDxI+grY26ZcA4VepEUJgVC7lL3I9jGGBHnOzwER8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1oq7Tw-00087G-Nt@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:44:12 +0000

commit fcba6c74e1493a329563208ed1f3014dab54bd47
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34)
---
 tools/xenstore/xenstored_core.c        | 25 +++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c952608468..e0d6d23f3b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -466,15 +466,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
@@ -977,18 +979,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	key.dptr = (void *)node->name;
-	key.dsize = strlen(node->name);
-
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 196a6fd2b0..9369c4cbfd 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -119,6 +119,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 2881f3b2e4..4ffa183111 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -582,6 +582,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:44:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:44:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435499.688852 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7U8-00063J-Cu; Wed, 02 Nov 2022 06:44:24 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435499.688852; Wed, 02 Nov 2022 06:44:24 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7U8-000639-8q; Wed, 02 Nov 2022 06:44:24 +0000
Received: by outflank-mailman (input) for mailman id 435499;
 Wed, 02 Nov 2022 06:44:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7U6-00062x-Sp
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7U6-0002s3-S4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7U6-00087h-R6
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=A96FrxhWrjL94wOgA6kl0mvNxNuiDlCrevWQlwDikvs=; b=1bq9RB8fKrM90w4v2aCzD+/dMX
	O1LagAOa0+gWOslQpIAt1KXPqkRRo1JCW1qpDYcDZgIz8/AZw9WzMoZ/7oc7v3rHzs0+60w9uTtSe
	r8jpfvYl8BKaLX4qt9w6LHmoiRF4oipfRRgbtioiVTCzAm/dngs1asd9ZoQPCnYxaohE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: split up send_reply()
Message-Id: <E1oq7U6-00087h-R6@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:44:22 +0000

commit 95fe444988f05f5b0d4fa5095a84842f83d87793
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32)
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 42 +++++++----------------
 3 files changed, 58 insertions(+), 59 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e0d6d23f3b..97ff35cd2b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -672,49 +672,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -722,8 +705,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 9369c4cbfd..2b0f796d9b 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -150,6 +150,7 @@ unsigned int get_strings(struct buffered_data *data,
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 9ff20690c0..6d8097376e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -72,37 +72,17 @@ static bool is_child(const char *child, const char *parent)
 	return child[len] == '/' || child[len] == '\0';
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
+static const char *get_watch_path(const struct watch *watch, const char *name)
 {
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
+	const char *path = name;
 
 	if (watch->relative_path) {
-		name += strlen(watch->relative_path);
-		if (*name == '/') /* Could be "" */
-			name++;
+		path += strlen(watch->relative_path);
+		if (*path == '/') /* Could be "" */
+			path++;
 	}
 
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
+	return path;
 }
 
 /*
@@ -181,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -252,7 +236,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:44:34 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:44:34 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435504.688867 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7UI-0006Lu-Ld; Wed, 02 Nov 2022 06:44:34 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435504.688867; Wed, 02 Nov 2022 06:44:34 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7UI-0006Lm-If; Wed, 02 Nov 2022 06:44:34 +0000
Received: by outflank-mailman (input) for mailman id 435504;
 Wed, 02 Nov 2022 06:44:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7UH-0006LP-0M
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7UG-0002sL-V4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7UG-00088A-UK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=qNNDmsnfOWAFbjnNzAALVBS2VAEGDvIMTd1fR5dnS/8=; b=1TLky/BGvSSOjYTUeukxpuVcak
	raK+8FGgolfNT5D2flSPx64Ahcm4ukUvXi8LK0UOnFYY3bvBT+/sATbo9Vl6N9tOdrrRd5zDjxF0S
	wrQ7FrNDCZWUrmD/xqnDiP6FxjsouHvfqDfJ96d6PqKzF54eBrfxKA+gDOmJbV0S9zDw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1oq7UG-00088A-UK@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:44:32 +0000

commit 6f311278e9f8082378e236ab246ae160d76db008
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ead062a68a9c201a95488e84750a70a107f7b317)
---
 tools/xenstore/xenstored_core.c   | 26 +++++++++++++++++---------
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c |  7 +------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 97ff35cd2b..11b8d98634 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -205,6 +205,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -248,8 +263,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
@@ -1389,18 +1403,12 @@ static struct {
  */
 static void ignore_connection(struct connection *conn)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored\n", conn);
 
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2b0f796d9b..83d49693fc 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -226,6 +226,8 @@ extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
 
+void conn_free_buffered_data(struct connection *conn);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index cbd8e6b747..416b92cad4 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -406,15 +406,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:44:44 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:44:44 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435505.688870 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7US-0006RN-NY; Wed, 02 Nov 2022 06:44:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435505.688870; Wed, 02 Nov 2022 06:44:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7US-0006RE-KC; Wed, 02 Nov 2022 06:44:44 +0000
Received: by outflank-mailman (input) for mailman id 435505;
 Wed, 02 Nov 2022 06:44:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7UR-0006QV-2V
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7UR-0002sW-1o
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7UR-00088o-1A
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=DqakM3i3sC+OxnpVAla58qYGFx038KjEY8ENfVe8Y5Q=; b=piupCG2/NL4ysIwDtRXKvOZRrx
	8WP3SRWi2xvEFrrt6ESam+/U5NH7SytTkoIXbbKwCHrxYZXWCai2UV+1D65niNC/kHzoupcNpeAU4
	63lWM3I3jNI3XfcQpCriXSmWz5qZm7FjiCkM13tbJnd0n0C+H/OZLBITfmICb8VJgEfQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: reduce number of watch events
Message-Id: <E1oq7UR-00088o-1A@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:44:43 +0000

commit 1761828e6d00110562bf869ae284c17f5496fc89
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297)
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 11b8d98634..8f8d10cee9 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1180,7 +1180,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1192,7 +1192,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1204,7 +1204,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1230,13 +1235,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 4ffa183111..6fbdb29dcd 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -329,6 +333,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -383,15 +410,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 6d8097376e..2f9367767e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:44:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:44:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435507.688875 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Ub-0006a6-Qc; Wed, 02 Nov 2022 06:44:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435507.688875; Wed, 02 Nov 2022 06:44:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Ub-0006Zx-NV; Wed, 02 Nov 2022 06:44:53 +0000
Received: by outflank-mailman (input) for mailman id 435507;
 Wed, 02 Nov 2022 06:44:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ub-0006Zo-5y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ub-0002sw-5B
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ub-00089N-4E
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:44:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=xbdNnpoNqu0O/54E9K3IuQFi+V8J2WoHWG8vuKqgQps=; b=YA5M59h/KGL002c2r23j/tsJlT
	cJSFCJeaURDsYUerEQnzFrqy3yPXQrJZGxD8lFFRU5dK3CJODlI492uzGEI7BLjc3sjhrjbSMlDBB
	WBWFuZVaqgySbv0pI8PQMkHQ1QyRDTbAcKDKb+iYsJreuzrqnT5z4DhDA/cPmczrhodA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: let unread watch events time out
Message-Id: <E1oq7Ub-00089N-4E@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:44:53 +0000

commit cde36e0c369d0156e5f441635a2c45c0e28d926f
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 5285dcb1a5c01695c11e6397c95d906b5e765c98)
---
 tools/xenstore/xenstored_core.c | 127 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8f8d10cee9..5fb4714b35 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -103,6 +103,8 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -205,19 +207,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -331,6 +406,7 @@ static void initialize_fds(int sock, int *p_sock_pollfd_idx,
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -352,10 +428,12 @@ static void initialize_fds(int sock, int *p_sock_pollfd_idx,
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (domain_can_read(conn) ||
 			    (domain_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -699,6 +777,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -750,6 +829,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -2009,6 +2094,9 @@ static void usage(void)
 "  -W, --watch-nb <nb>     limit the number of watches per domain,\n"
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2030,6 +2118,7 @@ static struct option options[] = {
 	{ "trace-file", 1, NULL, 'T' },
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2041,6 +2130,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt, *sock = NULL, *ro_sock = NULL;
@@ -2052,7 +2174,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2097,6 +2219,9 @@ int main(int argc, char *argv[])
 		case 'A':
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 83d49693fc..3112c11811 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <dirent.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -56,6 +57,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -88,6 +91,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -199,6 +203,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:45:03 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:45:03 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435509.688877 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Ul-0006gI-SF; Wed, 02 Nov 2022 06:45:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435509.688877; Wed, 02 Nov 2022 06:45:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Ul-0006gA-PE; Wed, 02 Nov 2022 06:45:03 +0000
Received: by outflank-mailman (input) for mailman id 435509;
 Wed, 02 Nov 2022 06:45:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ul-0006fx-9B
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ul-0002tW-8S
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ul-0008A8-7l
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=vYReEA9r4/nzQhI6gVev8vrvPAk/nGnFalvR7iT2tac=; b=tcZeY3BprVa1AcYVXzSU+OjIJJ
	w0Y4s2X0jLttk/ziLQ5+9Vrc8DDmIYuxHr3tTuxNbFAOloeNErcupBoVwvEqGF00uaDj96nNMVh8s
	8KjBscPMzwkrRu/yLoL3fd/Fxli/F9VTHkCI8W+xEAGP+dvdMS+Hl4rPgK2m/SArK7bk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: limit outstanding requests
Message-Id: <E1oq7Ul-0008A8-7l@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:45:03 +0000

commit 538b61b90393f21ba9ce8cc73fc9eb8fc046ade6
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 36de433a273f55d614c83b89c9a8972287a1e475)
---
 tools/xenstore/xenstored_core.c   | 78 ++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h   | 20 +++++++++-
 tools/xenstore/xenstored_domain.c | 37 ++++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 ++++++--
 5 files changed, 141 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5fb4714b35..5f1733112a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -102,6 +102,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -217,12 +218,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -238,6 +251,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -346,6 +383,7 @@ static bool write_messages(struct connection *conn)
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -359,6 +397,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -798,6 +841,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -805,7 +850,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -835,8 +881,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1572,6 +1623,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1642,6 +1694,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
 	new->is_ignored = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 
@@ -2094,6 +2147,9 @@ static void usage(void)
 "  -W, --watch-nb <nb>     limit the number of watches per domain,\n"
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2118,6 +2174,7 @@ static struct option options[] = {
 	{ "trace-file", 1, NULL, 'T' },
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2163,6 +2220,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt, *sock = NULL, *ro_sock = NULL;
@@ -2174,7 +2245,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2219,6 +2290,9 @@ int main(int argc, char *argv[])
 		case 'A':
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 3112c11811..edeaa96dd1 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -45,6 +45,8 @@ typedef int32_t wrl_creditt;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -52,6 +54,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -93,6 +106,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -154,7 +170,8 @@ unsigned int get_strings(struct buffered_data *data,
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -202,6 +219,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 416b92cad4..58b7e0fe2f 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -86,6 +86,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -288,8 +291,12 @@ bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	if (conn->is_ignored)
 		return false;
@@ -338,7 +345,7 @@ static struct domain *alloc_domain(void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -387,8 +394,6 @@ static int new_domain(struct domain *domain, int port)
 	domain->conn->id = domain->domid;
 
 	domain->remote_port = port;
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
 
 	return 0;
 }
@@ -929,6 +934,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5e00087206..4bff2e655b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -67,6 +67,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 2f9367767e..c50c0575f0 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -238,8 +241,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	talloc_set_destructor(watch, destroy_watch);
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:45:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:45:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435511.688883 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Uv-000743-Ui; Wed, 02 Nov 2022 06:45:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435511.688883; Wed, 02 Nov 2022 06:45:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Uv-00073w-R1; Wed, 02 Nov 2022 06:45:13 +0000
Received: by outflank-mailman (input) for mailman id 435511;
 Wed, 02 Nov 2022 06:45:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Uv-00073l-CM
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Uv-0002th-Bc
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Uv-0008Af-Av
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=GMTxUSWutWM81qGpqwskwtlrxTV3XpCW7qwLfK5VsNs=; b=lYojLMW6GSFV9d/WzOHwGcl4YO
	NeNQKTRZ5AFGj76an2+U+aY+p7iiXMRnlk8rN+Nnnvc3FvB4aL2/CII8tQa8WpfovOvTh6B8tz9jW
	r31Fe3+DRw1olpsliWpDwvUAajFqGrsqdilYsy43RruWcMkjSGU7uJbw7UD3LRwtNJhM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1oq7Uv-0008Af-Av@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:45:13 +0000

commit 2963ee5d065ecd2fb8c7a5dcd9f1cff66f6497f2
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2)
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5f1733112a..0621023bca 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -821,6 +821,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -853,7 +854,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -875,12 +876,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index edeaa96dd1..1eb6131fc8 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -51,6 +51,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:45:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:45:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435513.688886 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7V6-00079J-14; Wed, 02 Nov 2022 06:45:24 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435513.688886; Wed, 02 Nov 2022 06:45:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7V5-000799-Ub; Wed, 02 Nov 2022 06:45:23 +0000
Received: by outflank-mailman (input) for mailman id 435513;
 Wed, 02 Nov 2022 06:45:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7V5-00078z-FH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:23 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7V5-0002ts-EX
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:23 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7V5-0008B4-Dn
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:23 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9/u7PoBri7Eug9PkSXGi6iHepjhSAIAWyWim7QDLyFc=; b=kE6IEyqf6FtWQtC6Tnze6envHZ
	d4IepCCR7/fxJjCPQZruwPGWZrpzt1McXe7Ef+YSl/F8OpBe/MXd0q8RCXgYu+5y7EW4sPWWw8NiG
	ZXNFWXesbMPMSA1SF3fFxi9XxMtYQ464MdERCHvCq2uXswkSJWppu76o1MEOqDrVBeDg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: fix connection->id usage
Message-Id: <E1oq7V5-0008B4-Dn@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:45:23 +0000

commit e84ef3b0810c3fdf4db7728c69fca2dee77084a2
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831)
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index e4b8aa95ab..d3272e2ef9 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -180,7 +180,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	int cmd;
 	char **vec;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	num = xs_count_strings(in->buffer, in->used);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1eb6131fc8..98db4afcaa 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -93,7 +93,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this a read-only connection? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6fbdb29dcd..9bef6e72a5 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -483,7 +483,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:45:34 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:45:34 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435514.688890 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7VG-0007Cp-2f; Wed, 02 Nov 2022 06:45:34 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435514.688890; Wed, 02 Nov 2022 06:45:34 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7VF-0007Ch-WF; Wed, 02 Nov 2022 06:45:34 +0000
Received: by outflank-mailman (input) for mailman id 435514;
 Wed, 02 Nov 2022 06:45:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VF-0007CX-IY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VF-0002u2-Hu
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:33 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VF-0008Be-Gv
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:33 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=AGLt9nTgWpAmC7dv1dsKYr0XItpU8hLfExtGSf+ox6g=; b=jxFcv594jHQwnSjZrXKrk6FgCb
	pJ8RQAhpOasUoZBDBxT9nouzRv0uHQs5KJ+ib7S/No7HK64vgFphAT9T+8ezqsBKTErxhS+IjaRU9
	Pf7SbTjwp2lw0yJKxJIpPBe75yjfmk1jbIFt8u9lkiRBIEi9CLr2j+XN9IrLROaM3qtU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1oq7VF-0008Be-Gv@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:45:33 +0000

commit 5fa4f2c6c8dbc225824a6f9c407b11c510d98674
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit dbef1f7482894c572d90cd73d99ed689c891e863)
---
 tools/xenstore/xenstored_control.c     |   1 +
 tools/xenstore/xenstored_core.c        |  39 +++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 5 files changed, 107 insertions(+), 50 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index d3272e2ef9..715e0d2a9e 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -25,6 +25,7 @@
 #include "talloc.h"
 #include "xenstored_core.h"
 #include "xenstored_control.h"
+#include "xenstored_domain.h"
 
 struct cmd_s {
 	char *cmd;
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 0621023bca..98d242e062 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -543,7 +543,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -565,7 +565,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1159,13 +1159,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1215,8 +1219,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1497,10 +1505,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
 
-	if (write_node(conn, node, false))
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
+
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 58b7e0fe2f..f4134db3e7 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -362,6 +363,18 @@ static struct domain *alloc_domain(void *context, unsigned int domid)
 	return domain;
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port)
 {
 	int rc;
@@ -774,30 +787,28 @@ void domain_init(void)
 	virq_port = rc;
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -833,7 +844,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -843,8 +854,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -863,25 +880,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -891,13 +908,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4bff2e655b..4edf1dba94 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -57,10 +57,10 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 9bef6e72a5..bf2fda8234 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -523,8 +523,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:45:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:45:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435515.688894 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7VR-0007Fy-4T; Wed, 02 Nov 2022 06:45:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435515.688894; Wed, 02 Nov 2022 06:45:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7VR-0007Fr-1X; Wed, 02 Nov 2022 06:45:45 +0000
Received: by outflank-mailman (input) for mailman id 435515;
 Wed, 02 Nov 2022 06:45:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VP-0007FT-Lm
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VP-0002u8-L0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VP-0008C9-KE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=hN2G++DWeivpiS+3YHFVAVSyovKKaf5ll4rlouGAYrg=; b=soBrE6jV2B04X8/Jiw/bQ3DgXl
	WpFKnOtgklNi7FAvrU89NPIehrPYQk8A4fWXiBGJCfoHVqCHCdVXpf0T6jiktktJoS8nVbwqTxFZr
	HfS0riSP/zuPT1rZAwKdJY7Q4IuJigC1OTc1uRf5NgqTuTr5707BV8qVunMCyBzAVZps=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1oq7VP-0008C9-KE@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:45:43 +0000

commit f859218309f09ec6d425e02b583e4494924304ad
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 268369d8e322d227a74a899009c5748d7b0ea142)
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index cc7dfc8c64..34db3b7847 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -59,4 +59,8 @@
     })
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 98d242e062..57c9991292 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -102,6 +102,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
@@ -500,6 +501,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -521,14 +523,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -543,19 +544,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -670,7 +688,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -733,7 +751,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1115,7 +1133,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1394,7 +1412,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1422,7 +1440,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2192,6 +2210,8 @@ static void usage(void)
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2273,6 +2293,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 98db4afcaa..7e371253d2 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -34,6 +34,7 @@
 #include "list.h"
 #include "tdb.h"
 #include "hashtable.h"
+#include "utils.h"
 
 /* DEFAULT_BUFFER_SIZE should be large enough for each errno string. */
 #define DEFAULT_BUFFER_SIZE 16
@@ -223,6 +224,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index bf2fda8234..778b7e439c 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -266,6 +269,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -303,6 +311,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:45:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:45:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435516.688898 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Vb-0007Iq-6h; Wed, 02 Nov 2022 06:45:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435516.688898; Wed, 02 Nov 2022 06:45:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Vb-0007Ij-38; Wed, 02 Nov 2022 06:45:55 +0000
Received: by outflank-mailman (input) for mailman id 435516;
 Wed, 02 Nov 2022 06:45:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VZ-0007IW-Oo
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VZ-0002uV-O7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7VZ-0008Cm-NH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:45:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ET7D9C09FJp/9gtUPUUsxSXwGcN7JQyypWZ5Ru8d/zA=; b=UlBqDPM9n1nbecfkpq1YQUtHiT
	y2Ik/VSj6kY2+snQyqRD4Xra6cHBgS8THjcgwPRGiSOwkkwZLI6iOx6vliCuV8tz0S1FWENrBKPVB
	MdK55lnjhsqnLPuTCHQmYxceYIxCLL/Zt1jab6FNtU3XaXUmeJyS1oX9uobheu0Pxt3M=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1oq7VZ-0008Cm-NH@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:45:53 +0000

commit 8cd25aecce59e420b25a75b5643a8d668ee22c4c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 60e2f6020dea7f616857b8fc1141b1c085d88761)
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 2 ++
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 57c9991292..1335051a53 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1832,7 +1832,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -1871,7 +1872,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(void)
+void setup_structure(void)
 {
 	char *tdbname;
 	tdbname = talloc_strdup(talloc_autofree_context(), xs_daemon_tdb());
@@ -1889,6 +1890,7 @@ static void setup_structure(void)
 	manual_node("/", "tool");
 	manual_node("/tool", "xenstored");
 	manual_node("/tool/xenstored", NULL);
+	domain_entry_fix(dom0_domid, 3, true);
 
 	check_store();
 }
@@ -2402,9 +2404,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure();
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init)
 		domain_init();
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 7e371253d2..d95e4262a9 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -195,6 +195,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(void);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 void check_store(void);
 void corrupt(struct connection *conn, const char *fmt, ...);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index f4134db3e7..8bf9db2d96 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -739,6 +739,8 @@ static int dom0_init(void)
 	if (dom0->interface == NULL)
 		return -1;
 
+	setup_structure();
+
 	talloc_steal(dom0->conn, dom0); 
 
 	xenevtchn_notify(xce_handle, dom0->port);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:46:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:46:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435517.688902 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Vl-0007Nf-9P; Wed, 02 Nov 2022 06:46:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435517.688902; Wed, 02 Nov 2022 06:46:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Vl-0007NY-6b; Wed, 02 Nov 2022 06:46:05 +0000
Received: by outflank-mailman (input) for mailman id 435517;
 Wed, 02 Nov 2022 06:46:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Vj-0007NC-S9
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Vj-0002v7-RP
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Vj-0008DW-QW
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Beivdey3h7399s2lDGeT4AxlTT3a7YdV4bZlst+wtI4=; b=v9+HXoSQPIKYe0utATgLdcJHYz
	qmmZVGBc26ApGYSx7CkujpYcBs8PwJjdjYsOQAt9aHcr/LD9AMuHsj68/nrsiJellwFiOqSnRv84V
	v/j3Enshwr2ec2LND7XLFin1imfdAH/hcTygBdJTcJkkuH5rl+INHTsuVxzFIFopW8ZU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1oq7Vj-0008DW-QW@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:46:03 +0000

commit b917d57d46c3769f6b482d70c6a54a5dbdd7d87a
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d4a8ec7a93faedbe54fd197db146de628459e77)
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 1335051a53..217096d91a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -104,6 +104,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2214,7 +2216,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2240,6 +2249,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2285,7 +2295,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2293,11 +2303,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2312,7 +2327,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2358,7 +2373,10 @@ int main(int argc, char *argv[])
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index d95e4262a9..4e53072e63 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -226,6 +226,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8bf9db2d96..2b23452e0c 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -84,6 +84,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -297,6 +304,9 @@ bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	if (conn->is_ignored)
@@ -941,6 +951,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4edf1dba94..3a8c6bab48 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,6 +64,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:46:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:46:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435518.688906 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Vv-0007R7-As; Wed, 02 Nov 2022 06:46:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435518.688906; Wed, 02 Nov 2022 06:46:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Vv-0007Qz-8D; Wed, 02 Nov 2022 06:46:15 +0000
Received: by outflank-mailman (input) for mailman id 435518;
 Wed, 02 Nov 2022 06:46:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Vt-0007Qk-VH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Vt-0002vH-UW
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Vt-0008Dx-To
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=E3SKWxkWEgMJmsTqJpU3qnTGcAR9KhshgKRgCQXhqZQ=; b=uffxxKTXeKRwUFvfKgL1I5sY+7
	Qsx3131f8HzDLTcAkI2laknypTCBj+OQwZA4zJdCBRwP8eBJJIf9AM9eyU7O0LY2HgbZfU9rwsw0+
	oXyHGb5++/XX5fm4R1S4hM1y4FdmXxQO6OwlKUnHLHrsah2EAnuD1IvPS2btF4hKTCgI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: add memory accounting for responses
Message-Id: <E1oq7Vt-0008Dx-To@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:46:13 +0000

commit 115156c416ad9a12d72d14f2df0c982ea1a254c4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    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 f6d00133643a524d2138c9e3f192bbde719050ba)
---
 tools/xenstore/xenstored_core.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 217096d91a..4f29439ad8 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -254,6 +254,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -843,11 +845,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -912,6 +917,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:46:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:46:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435519.688910 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7W5-0007U3-CT; Wed, 02 Nov 2022 06:46:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435519.688910; Wed, 02 Nov 2022 06:46:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7W5-0007Tu-9g; Wed, 02 Nov 2022 06:46:25 +0000
Received: by outflank-mailman (input) for mailman id 435519;
 Wed, 02 Nov 2022 06:46:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7W4-0007Tk-1y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7W4-0002vL-1I
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7W4-0008EM-0W
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=HZ6VED9oxDw/UFhH9F8rIfWnH1kWsvcXr+1ixvcH9Zc=; b=iiQzxcX/2rSxHuQb+4CTI4Np1x
	b9rkyagKaV10ihSMY57/E7166W+iH602TI7WF2SsWKs/wJLgXSs4972a8D1Ql4smgYfEAj9r5CluC
	9QLHpFWZ1IvtZCH3YNAT6EUSnXv6axf+LKiQDJ1av9dJkI1kCVdiCKidc6OFUlONdQJc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: add memory accounting for watches
Message-Id: <E1oq7W4-0008EM-0W@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:46:24 +0000

commit c17d49134aef23c8d017a64e5e36c626779bf863
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    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 7f9978a2cc37aaffab2fb09593bc598c0712a69b)
---
 tools/xenstore/xenstored_core.c  | 1 +
 tools/xenstore/xenstored_watch.c | 7 ++++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 4f29439ad8..eca04e734a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -404,6 +404,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index c50c0575f0..7118c30e8c 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -224,7 +224,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 		return ENOMEM;
 	watch->node = talloc_strdup(watch, vec[0]);
 	watch->token = talloc_strdup(watch, vec[1]);
-	if (!watch->node || !watch->token) {
+	if (!watch->node || !watch->token ||
+	    domain_memory_add_chk(conn->id, strlen(vec[0]) + strlen(vec[1]))) {
 		talloc_free(watch);
 		return ENOMEM;
 	}
@@ -265,6 +266,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -280,6 +283,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:46:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:46:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435520.688914 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7WF-0007XA-Dq; Wed, 02 Nov 2022 06:46:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435520.688914; Wed, 02 Nov 2022 06:46:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7WF-0007X2-BD; Wed, 02 Nov 2022 06:46:35 +0000
Received: by outflank-mailman (input) for mailman id 435520;
 Wed, 02 Nov 2022 06:46:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WE-0007Wn-58
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WE-0002va-4Q
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WE-0008El-3h
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=XyZbzIAlFKBokAR6Da1tpqqjduHlJ2GqaDrcheRhWcM=; b=XaMRfqaQ3FLEOEJzeTM0X+6yi0
	DC1sHBu5HWfgTKMCKT9MPrwlDFnPRkzh/YyOHoWNUUrer+1uuy3LglshbRl7eCZ5B0a8XHfrbuL20
	QtzWZ7l5+LbG7w/GwOkves7ZpVq2HDRh1y5oRysE6pJuxEYLi2Ub7xUntuXpFdsMO1tk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: add memory accounting for nodes
Message-Id: <E1oq7WE-0008El-3h@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:46:34 +0000

commit 7dc06ed1f2ab191ec03e892329be90ecdcd764c8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    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        | 139 ++++++++++++++++++++++++++++++---
 tools/xenstore/xenstored_core.h        |  13 +++
 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 eca04e734a..2c0f8fd99b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -496,6 +496,117 @@ static void initialize_fds(int sock, int *p_sock_pollfd_idx,
 	}
 }
 
+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.
@@ -549,9 +660,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. */
@@ -615,12 +732,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;
 }
 
@@ -1119,7 +1233,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;
 	}
@@ -1182,6 +1296,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;
 
@@ -1190,17 +1305,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);
 
 	/*
@@ -1252,7 +1367,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;
 			}
 		}
@@ -2075,7 +2190,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);
 		}
 	}
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 4e53072e63..521bc80384 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -141,6 +141,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 */
@@ -163,6 +168,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. */
@@ -258,6 +266,11 @@ extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
 
+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);
 
 #endif /* _XENSTORED_CORE_H */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 778b7e439c..c1beb40a3d 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;
 
@@ -292,6 +295,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
@@ -416,11 +421,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;
@@ -431,7 +436,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);
@@ -459,7 +464,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);
@@ -503,6 +508,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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:46:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:46:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435521.688918 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7WP-0007aa-HM; Wed, 02 Nov 2022 06:46:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435521.688918; Wed, 02 Nov 2022 06:46:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7WP-0007aO-E8; Wed, 02 Nov 2022 06:46:45 +0000
Received: by outflank-mailman (input) for mailman id 435521;
 Wed, 02 Nov 2022 06:46:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WO-0007aE-89
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WO-0002xH-7O
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WO-0008FB-6o
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=GtCXDuSnw71Okfl6MywQEVEWxMA1y4KqLcxoVSk4ETs=; b=hJEqtMBhhvM/TDH/KzDoRKMKrv
	GbFgTlZjVdzbz1FsYFyscdMXhYXjYWgTB2iWGf7YiVcYIMDJAZJHKTI99lb4Clad9rQjCzwBPOl9P
	Oyzj+pUhJqvoUPI9EuuF6gnkKGqTQyHQE9olseeeBj0iDoVL+frMel7yjHFxfjbdAfhI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: add exports for quota variables
Message-Id: <E1oq7WO-0008FB-6o@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:46:44 +0000

commit 146b9544fbef9d5d2e7a8e072d3d40d5065294f2
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 1da16d5990b5f7752657fca3e948f735177ea9ad)
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 521bc80384..5abf06c21c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -231,6 +231,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index c1beb40a3d..6e29118c80 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static void set_tdb_key(const char *name, TDB_DATA *key)
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 7118c30e8c..19d0fb01b1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:46:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:46:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435522.688924 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7WZ-0007dL-It; Wed, 02 Nov 2022 06:46:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435522.688924; Wed, 02 Nov 2022 06:46:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7WZ-0007dC-Fc; Wed, 02 Nov 2022 06:46:55 +0000
Received: by outflank-mailman (input) for mailman id 435522;
 Wed, 02 Nov 2022 06:46:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WY-0007d0-B5
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WY-0002xh-AS
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7WY-0008Fb-9l
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:46:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=SBHaUMReg9pXE6Gyog4Z9PcD09sC4/aO4GC7Ow5lJYo=; b=LKaXxcaCTTnEMWILIk7rM3O+2d
	crQcYTTlPqhh92EHX5f1PMnLSy+pTqGp9h5N+en+pygNPDC+jQLYFJ7Nt5sqekzHwIwv0KmICD8ag
	2MSq2XOOocYtB1YvM7Ybiv5CT0s/HzPU04yhC0h/xu0FJWR9bgt1aH2PWcg6cCvEcWH0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1oq7WY-0008Fb-9l@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:46:54 +0000

commit 63dc2a18f8ff098efbae76dde431938d5be20462
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 32969eb3fe..0dbac442d7 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -346,6 +346,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 715e0d2a9e..454fe9d5ab 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "utils.h"
@@ -77,6 +78,114 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
 {
@@ -136,6 +245,8 @@ static struct cmd_s cmds[] = {
 	{ "logfile", do_control_logfile, "<file>" },
 	{ "memreport", do_control_memreport, "[<file>]" },
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 2b23452e0c..4b2da302c2 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -352,6 +353,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 3a8c6bab48..e013a9991c 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -90,6 +90,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:47:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:47:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435523.688926 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Wj-0007hx-KS; Wed, 02 Nov 2022 06:47:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435523.688926; Wed, 02 Nov 2022 06:47:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Wj-0007hp-HO; Wed, 02 Nov 2022 06:47:05 +0000
Received: by outflank-mailman (input) for mailman id 435523;
 Wed, 02 Nov 2022 06:47:04 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Wi-0007hb-E7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:04 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Wi-0002y4-DR
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Wi-0008GB-Cj
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=IusVZZ9rDH15fc0jFylV3GWmTfm/Cb3oYtFpiGnvh9w=; b=QGJWv9NTBcmBnp0ebSkb3Xj8Fq
	1lSKPCers9cZh1sja0P1/drePc6s0exNI+1OXRbMRuXYR9g5ZttNE4T2LOF3M2iJdz6eUsuv63C/Q
	s2sjia6P7mQgmHwXGDcbd3QHtH0NPSXekOY0hOiBxG4NYrYvKG3BCfFx75fpuLgQdPYk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1oq7Wi-0008GB-Cj@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:47:04 +0000

commit d71e4eca23e1b545e39a1418f07cbdece3fa0c4c
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 84734955d4bf629ba459a74773afcde50a52236f)
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index f574397a4c..96c125a969 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -22,9 +22,9 @@ let xs_daemon_socket_ro = Paths.xen_run_stored ^ "/socket_ro"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:47:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:47:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435524.688930 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Wt-0007kn-Ll; Wed, 02 Nov 2022 06:47:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435524.688930; Wed, 02 Nov 2022 06:47:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Wt-0007kf-Iy; Wed, 02 Nov 2022 06:47:15 +0000
Received: by outflank-mailman (input) for mailman id 435524;
 Wed, 02 Nov 2022 06:47:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ws-0007kX-H4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:14 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ws-0002yE-GN
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:14 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ws-0008Gi-Fi
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:14 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=QBAZLEr+2GPwHbsn6Ou8pJ21l96Uoth6oT+u5LBmx6o=; b=7NyhiT+dq/km/xoR0quxYjfcF/
	j8OeyrOZiZuDLs2/bFOFpOIL/6p3RfdtybpkOdfoBmSDuJ+ixcXQE3M6mC8T3OmF+uM9kgabDEM23
	NdOuZ3e2XR0uQab9BQAT6cPryf9njRaTF+gxkHTuCGHSQQsSRaEAY5s1MPJBBIuYAcY4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1oq7Ws-0008Gi-Fi@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:47:14 +0000

commit c084ee8e5834a33fba8e03fe9bcd1e1ebe03b09d
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    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 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff)
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 3ab09c6ce9..3279b19b1b 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:47:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:47:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435526.688934 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7X3-0007ns-N7; Wed, 02 Nov 2022 06:47:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435526.688934; Wed, 02 Nov 2022 06:47:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7X3-0007nj-KW; Wed, 02 Nov 2022 06:47:25 +0000
Received: by outflank-mailman (input) for mailman id 435526;
 Wed, 02 Nov 2022 06:47:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7X2-0007nV-Jr
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7X2-0002yL-JG
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7X2-0008HD-Ia
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=A31psfsEqd+CX4Ll42iwAHCZTQtlTPygz0sldt7sbDI=; b=aT0K7agn+2wRwpNj0mwu5979cU
	Lc7mbeG0rp27n83eN9iOfa+Stz54MaUGjDSVrCtvA+P9M6Jq9ZomWcXj9lipRR5UeNf6HC/W+0rUh
	eTkMSw9s8NIWe3JLxyen0pdiUVm/9DpVuEl0q1BAqf83hyk7seqTTqMZ1C8lKlA7PRMQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml: GC parameter tuning
Message-Id: <E1oq7X2-0008HD-Ia@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:47:24 +0000

commit bc93157f7b3b571b44bce0ecf7328c82c7aca78b
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 4a8bacff20b857ca0d628ef5525877ade11f2a42)
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 96c125a969..1a5d2f34a6 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -26,6 +26,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 369b5036f4..0b6343dfc7 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -229,6 +230,67 @@ let to_file store cons file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -238,6 +300,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:47:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:47:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435527.688938 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7XD-0007r9-Q1; Wed, 02 Nov 2022 06:47:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435527.688938; Wed, 02 Nov 2022 06:47:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7XD-0007r1-NQ; Wed, 02 Nov 2022 06:47:35 +0000
Received: by outflank-mailman (input) for mailman id 435527;
 Wed, 02 Nov 2022 06:47:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XC-0007qo-Mz
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XC-0002yU-MK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XC-0008Hc-LX
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=pvc9y9RUmEMGjtDUOzvRczHKTTpQjPVYeMht3c8EFpI=; b=EtETjCz8oxnNfFpTAluOZgXpk6
	UcumFhx9FkPxM42f1/rplFgWj7Tvow/i5n92TANWhoF8d2/wF0wJVqPl1ICl6xAV420JpbG1zoIgd
	MGTFQ32InJwW6J/x1LAnXTVtFazmMPlJn9tj56oft3q+AQ1Xy+Hng6m1ekMUgWH2Uze0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml/libs/xb: hide type of Xb.t
Message-Id: <E1oq7XC-0008Hc-LX@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:47:34 +0000

commit 0135300160627cd502d9179ab79da1c631dca6f0
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Fri Jul 29 18:53:29 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml/libs/xb: hide type of Xb.t
    
    Hiding the type will make it easier to change the implementation
    in the future without breaking code that relies on it.
    
    No functional change.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba)
---
 tools/ocaml/libs/xb/xb.ml           | 3 +++
 tools/ocaml/libs/xb/xb.mli          | 9 ++-------
 tools/ocaml/xenstored/connection.ml | 4 +---
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 104d319d77..8404ddd8a6 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out
 let input_len con = Queue.length con.pkt_in
 let has_in_packet con = Queue.length con.pkt_in > 0
 let get_in_packet con = Queue.pop con.pkt_in
+let has_partial_input con = match con.partial_in with
+	| HaveHdr _ -> true
+	| NoHdr (n, _) -> n < Partial.header_size ()
 let has_more_input con =
 	match con.backend with
 	| Fd _         -> false
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 3a00da6cdd..794e35bb34 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,13 +66,7 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
-type t = {
-  backend : backend;
-  pkt_in : Packet.t Queue.t;
-  pkt_out : Packet.t Queue.t;
-  mutable partial_in : partial_buf;
-  mutable partial_out : string;
-}
+type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
 val queue : t -> Packet.t -> unit
@@ -97,6 +91,7 @@ val has_output : t -> bool
 val peek_output : t -> Packet.t
 val input_len : t -> int
 val has_in_packet : t -> bool
+val has_partial_input : t -> bool
 val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index daf8d804f7..70c4348552 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -125,9 +125,7 @@ let get_perm con =
 let set_target con target_domid =
 	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
 
-let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with
-	| Xenbus.Xb.Xenmmap _ -> true
-	| _ -> false
+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
 let send_reply con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:47:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:47:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435528.688941 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7XN-0007tt-RR; Wed, 02 Nov 2022 06:47:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435528.688941; Wed, 02 Nov 2022 06:47:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7XN-0007tk-Ou; Wed, 02 Nov 2022 06:47:45 +0000
Received: by outflank-mailman (input) for mailman id 435528;
 Wed, 02 Nov 2022 06:47:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XM-0007tY-Q4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XM-0002yr-PP
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XM-0008I1-Ok
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Vzoa2XaCpgsn3Gb5UE5pg4p8OCI8AZFUp1Gso5MOyvo=; b=SGRQ9Pt7KVHQSdf2Sj0UIMenJx
	JFYDgxWyPNS1H7drvRxeUfcqQ4scHCw/rCU8PGLyjQsXNVDrjwYat1pxrI0uyUYaxiAE6xgukx3hX
	z5bLbRI5Y0gJDIoblK/0BEYJF7CsMkITRBbqTJ9g49OjkIrOk2Ouw6T69S4w3OhQW/18=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1oq7XM-0008I1-Ok@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:47:44 +0000

commit c3c5f0aa4684d436accc314f69a585e8bc7fffea
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c0a86a462721008eca5ff733660de094d3c34bc7)
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  2 --
 tools/ocaml/xenstored/process.ml    | 12 ++++++------
 5 files changed, 18 insertions(+), 39 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 70c4348552..ace2aa5b4f 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,8 +277,6 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 3279b19b1b..72629ee38b 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -570,16 +570,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -589,8 +590,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:47:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:47:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435529.688946 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7XX-0007wb-TF; Wed, 02 Nov 2022 06:47:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435529.688946; Wed, 02 Nov 2022 06:47:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7XX-0007wU-QO; Wed, 02 Nov 2022 06:47:55 +0000
Received: by outflank-mailman (input) for mailman id 435529;
 Wed, 02 Nov 2022 06:47:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XW-0007w9-St
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XW-0002z2-SH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7XW-0008IQ-Rb
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:47:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=wPphO9Dj16klqPCo2osbgBd3M6TNpXRCcVWwAak9HPk=; b=Z7wcdjI7MbLVqgmbh0bwto/G/q
	mT4SL1R1bKKAelyWy/4B036VrO5v/z46wac+fy3D9SUKnYaqlyUKS0wIyGE4iLLQbY3AJYRF2iLtg
	ZQ4fDeEOBiPu9+GORfbf6hNkMNLphhh2V6zrHNqfgaCS4FKNhDObPObdtd9dvfbd6cws=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1oq7XW-0008IQ-Rb@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:47:54 +0000

commit 723e24871833406093b6a8e2e5b9a3d8de2e5e04
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 19171fb5d888b4467a7073e8febc5e05540956e9)
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:48:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:48:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435530.688949 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Xi-0007zw-Ul; Wed, 02 Nov 2022 06:48:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435530.688949; Wed, 02 Nov 2022 06:48:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Xi-0007zp-SB; Wed, 02 Nov 2022 06:48:06 +0000
Received: by outflank-mailman (input) for mailman id 435530;
 Wed, 02 Nov 2022 06:48:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Xh-0007zb-2F
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Xg-0002zL-Vb
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Xg-0008J5-Ur
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=vqnrTQ8L5n0cvHWJaeRzm/vyPx/S5hs7JVVtduRfJhs=; b=lFq9rH62RxwlrSItd6jOB9MNqH
	PgUkunRnbqkk5v/pF/1HUYvBIpTBxHw5mvBQy+IX9QCBQC2Qzjv46hRpaylB6aKLnvMCo7InWRTvy
	j/2EHJMA75RNfLHn6Sl/1GiQJEQRYJsRKF+BD5SCyZfDipLozDzqO/rD8UvKEzsjme7U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1oq7Xg-0008J5-Ur@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:48:04 +0000

commit 0252d044fcd4320450d3cef6c13492ef2faec2a1
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96)
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index ace2aa5b4f..9aad451a2d 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -279,6 +407,7 @@ let get_transaction con tid =
 let do_input con = Xenbus.Xb.input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -286,7 +415,7 @@ let peek_output con = Xenbus.Xb.peek_output con.xb
 let do_output con = Xenbus.Xb.output con.xb
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 7efdf3e5e0..39190c19ec 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: (string, Connection.watch list) Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd _can_write =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -196,3 +215,13 @@ let debug cons =
 	let anonymous = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.anonymous [] in
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
+
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 1a5d2f34a6..9e52367094 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 72629ee38b..d2a3ba064e 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -56,7 +56,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -66,8 +66,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -99,6 +100,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -207,7 +222,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -366,7 +381,7 @@ let do_watch con t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -397,7 +412,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -565,7 +580,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -593,6 +609,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 0b6343dfc7..4f8fab2dd1 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -102,6 +102,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:48:17 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:48:17 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435531.688954 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Xt-00083G-2I; Wed, 02 Nov 2022 06:48:17 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435531.688954; Wed, 02 Nov 2022 06:48:17 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Xs-000838-Vq; Wed, 02 Nov 2022 06:48:16 +0000
Received: by outflank-mailman (input) for mailman id 435531;
 Wed, 02 Nov 2022 06:48:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Xr-00082s-35
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Xr-0002zV-2N
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Xr-0008JW-1e
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=c6kYXwW87w0TK69XAQNADhXky2RfPLaJnEPM75fhykw=; b=QN47JE4JKW3ICK1PVYiXumE6qx
	LBpZr+UQb1SsVNK8UQJQvvkpkqgknfF+XTVDzxkQP8M5808nQyjxfHKbBauLOG88k2TvDzud09SMM
	6b8hiYPoMZplBYmXofrgt3OYRxXiepurANeWd0tQI30pu5HLq3Xo+h3WGAbyChFkziDc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1oq7Xr-0008JW-1e@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:48:15 +0000

commit e30f7c6b6b8e08ec4dfc7ca9ffdc556e597182c4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c7bc20d8d123851a468402bbfc9e3330efff21ec)
---
 SUPPORT.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/SUPPORT.md b/SUPPORT.md
index 3f4a01101e..2db341c1d8 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -149,6 +149,17 @@ Output of information in machine-parseable JSON format
 
     Status: Supported
 
+## Xenstore
+
+### C xenstored daemon
+
+    Status: Supported
+
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+
 ## Toolstack/3rd party
 
 ### libvirt driver for xl
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:48:27 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:48:27 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435532.688958 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Y3-00086I-42; Wed, 02 Nov 2022 06:48:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435532.688958; Wed, 02 Nov 2022 06:48:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Y3-00086A-17; Wed, 02 Nov 2022 06:48:27 +0000
Received: by outflank-mailman (input) for mailman id 435532;
 Wed, 02 Nov 2022 06:48:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Y1-00085z-6D
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Y1-0002zg-5X
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Y1-0008Jv-4o
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=YpPN+1krrzxdiNfYtLuA7MHyD6ZCRJSRZkiSf5+w/Z8=; b=JRiF/ggqbibe8mcjuxQxQfOsnq
	RByQcSb4Pfnjvm45OF7U1PervIBJH5+LBFYuEML6mFsdrV6xkYFwMFggh+vBlbtYXO6Go//X5Qp3g
	r0CcjlvpSxuUX/7hxuhq04Pgjy5MLg93uG1r+/gTUcROoEXy2fIexMErcfI3ZmZIRUw8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1oq7Y1-0008Jv-4o@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:48:25 +0000

commit 2fdf8740b9f47e424952869406261962db428b97
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2a587de219cc0765330fbf9fac6827bfaf29e29b)
---
 tools/xenstore/xenstored_control.c     | 27 ++++++------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 27 +++++++-----
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 115 insertions(+), 74 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 454fe9d5ab..3585d7c695 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -30,11 +30,11 @@
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -46,7 +46,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -63,7 +63,7 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -162,7 +162,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -174,7 +174,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -186,7 +186,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 	return EINVAL;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -225,7 +225,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -237,7 +237,7 @@ static int do_control_print(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -250,7 +250,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd, len = 0;
@@ -286,7 +286,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	int num;
 	int cmd;
@@ -298,7 +299,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (num < 1)
 		return EINVAL;
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) != num)
@@ -306,7 +307,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 
 	for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++)
 		if (streq(vec[0], cmds[cmd].cmd))
-			return cmds[cmd].func(in, conn, vec + 1, num - 1);
+			return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 
 	return EINVAL;
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index 207e0a6fa3..faa955968d 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,4 +16,5 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2c0f8fd99b..d6bbb532fb 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1145,11 +1145,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1158,7 +1160,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1170,7 +1172,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1197,7 +1200,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1213,11 +1216,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1397,7 +1402,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1411,12 +1417,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1427,18 +1433,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1446,10 +1453,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 		/* No permissions? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1547,22 +1554,23 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1577,7 +1585,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1587,13 +1595,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1606,7 +1616,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1623,7 +1634,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1638,7 +1649,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1673,7 +1684,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1681,7 +1692,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1754,6 +1766,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	if ((unsigned int)type >= XS_TYPE_COUNT || !wire_funcs[type].func) {
 		eprintf("Client unknown operation %i", type);
@@ -1774,10 +1787,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 4b2da302c2..3e2f49985a 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -337,7 +337,7 @@ bool domain_can_write(struct connection *conn)
 	return ((intf->rsp_prod - intf->rsp_cons) != XENSTORE_RING_SIZE);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -479,7 +479,8 @@ static void domain_conn_reset(struct domain *domain)
 }
 
 /* domid, mfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -558,7 +559,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -605,7 +607,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -620,7 +623,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -635,7 +639,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -643,18 +648,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -675,7 +679,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index e013a9991c..732eb8fa75 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -22,25 +22,32 @@
 void handle_event(void);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(void);
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6e29118c80..cd592845e7 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -487,7 +487,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -500,8 +501,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -548,7 +549,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -564,8 +566,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	list_del(&trans->list);
 	conn->transaction_started--;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 19d0fb01b1..13627ce972 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -184,7 +184,7 @@ static int destroy_watch(void *_watch)
 	return 0;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -200,7 +200,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 		/* check if valid event */
 	} else {
 		relative = !strstarts(vec[0], "/");
-		vec[0] = canonicalize(conn, in, vec[0]);
+		vec[0] = canonicalize(conn, ctx, vec[0]);
 		if (!vec[0])
 			return ENOMEM;
 		if (!is_valid_nodename(vec[0]))
@@ -250,7 +250,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -258,7 +259,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 03094374f3..40455dff5d 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:48:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:48:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435533.688962 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7YD-00089B-5s; Wed, 02 Nov 2022 06:48:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435533.688962; Wed, 02 Nov 2022 06:48:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7YD-000893-2d; Wed, 02 Nov 2022 06:48:37 +0000
Received: by outflank-mailman (input) for mailman id 435533;
 Wed, 02 Nov 2022 06:48:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YB-00088d-9B
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YB-0002zt-8Y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YB-0008KK-7w
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=EJjHWZ2j6bDT8hrm3bC/BgmucZxIjs8aLoOU7HN3py8=; b=jBA2l5moFKGEmaaJFXaoUfIz8n
	RfWaDJ6ZBm3YlBQWF4a1cGEMjwUMAVuOGHAIAZRNeVKO1BZRTPBRP4Ih4GI088KdZVEKFbRN1CrsY
	tAti5054CLc21Zm5ipXl4HogME+sOaw0ZlzXtD8yjVhzMRvdchcf0U8egfSubz0dVess=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: fix checking node permissions
Message-Id: <E1oq7YB-0008KK-7w@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:48:35 +0000

commit e6655e8f25e4ebf3d3cabac2430c8d5ba33a15a5
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ab128218225d3542596ca3a02aee80d55494bef8)
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index d6bbb532fb..25064427be 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1640,6 +1640,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3e2f49985a..43fc2c4879 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -866,7 +866,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -874,20 +873,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -900,8 +917,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -918,8 +933,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 732eb8fa75..bab405209e 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,6 +65,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:48:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:48:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435534.688965 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7YN-0008Ci-8i; Wed, 02 Nov 2022 06:48:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435534.688965; Wed, 02 Nov 2022 06:48:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7YN-0008Ca-65; Wed, 02 Nov 2022 06:48:47 +0000
Received: by outflank-mailman (input) for mailman id 435534;
 Wed, 02 Nov 2022 06:48:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YL-0008CO-CB
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YL-00030P-BY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YL-0008Kj-Au
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=6EGUplWLv8H1RsnJpJ12yK01snLEwWrX+qenZ+xlccQ=; b=DKb28JYQvUJ9AmOzO3IMRnOcjb
	aF7b7uFTLfcTek75V+E3IbLZDJflKjQ9r8iN4nfwMTdW0KoZ9uwxFkcYfj6plsXvRBhMw7P7yZZ8X
	DKnid5z9j/7vXGty2qB2Eme73X+PcavWhhFQMQN5Dw/6xzXb4geUPvJ99RSwpY02cv+E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1oq7YL-0008Kj-Au@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:48:45 +0000

commit b97e59f10d6f16b329ee95979cbc1b504bab076d
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 110 ++++++++++++++++++++++++++--------------
 1 file changed, 72 insertions(+), 38 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 25064427be..8ae0842ca3 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1252,57 +1252,91 @@ static char *basename(const char *name)
 	return strrchr(name, '/') + 1;
 }
 
-static struct node *construct_node(struct connection *conn, const void *ctx,
-				   const char *name)
+static int add_child(const void *ctx, struct node *parent, const char *name)
 {
 	const char *base;
 	unsigned int baselen;
-	struct node *parent, *node;
-	char *children, *parentname = get_parent(ctx, name);
-
-	if (!parentname)
-		return NULL;
+	char *children;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
-
-	/* Add child to parent. */
 	base = basename(name);
 	baselen = strlen(base) + 1;
 	children = talloc_array(ctx, char, parent->childlen + baselen);
 	if (!children)
-		goto nomem;
+		return ENOMEM;
 	memcpy(children, parent->children, parent->childlen);
 	memcpy(children + parent->childlen, base, baselen);
 	parent->children = children;
 	parent->childlen += baselen;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
-
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
-
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
+	return 0;
+}
+
+static struct node *construct_node(struct connection *conn, const void *ctx,
+				   const char *name)
+{
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
+
+	if (!parentname)
+		return NULL;
+
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
+
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
+
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
+
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
+
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:48:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:48:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435535.688970 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7YX-0008FM-A2; Wed, 02 Nov 2022 06:48:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435535.688970; Wed, 02 Nov 2022 06:48:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7YX-0008FF-7W; Wed, 02 Nov 2022 06:48:57 +0000
Received: by outflank-mailman (input) for mailman id 435535;
 Wed, 02 Nov 2022 06:48:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YV-0008Eq-F9
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YV-00030Z-EW
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7YV-0008Mk-Dr
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:48:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=cLqkp3mpQaT9OJ49A9Ch4K2xlWCV0shR0paCsdt9t8Q=; b=WQa5RtzV7bIaXZEOaxbFJGUSGF
	qeusj+Ts4aQCw5bJ2EvNEUzXNaJBjfRqVJg/VjKROqv/+vJt74KNq9QbaJxNDRGFkHg9a1bi6jeHZ
	diUwhVSCA6TU/aNrAbNkI6dKg6MtqgbwzHTGqnSSLVbXRs94qPXnYqCML0MRIZ6eOisc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1oq7YV-0008Mk-Dr@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:48:55 +0000

commit e2b7fa7508d7bff94ea72def2bb85c264065b2c0
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4)
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8ae0842ca3..006af15765 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1503,15 +1503,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1521,7 +1521,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2123,6 +2125,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2171,12 +2184,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2193,11 +2201,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:49:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:49:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435536.688974 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Yh-0008IW-Bl; Wed, 02 Nov 2022 06:49:07 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435536.688974; Wed, 02 Nov 2022 06:49:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Yh-0008IM-8y; Wed, 02 Nov 2022 06:49:07 +0000
Received: by outflank-mailman (input) for mailman id 435536;
 Wed, 02 Nov 2022 06:49:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yf-0008Hx-JD
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yf-00030y-Ha
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yf-0008NI-Gx
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5cAfgQltCVlEaIJ6YBWsLR6GV5fPNRF+T5pDWorUs1g=; b=hTa3tPgnDsfU+gFWHYdO9cv4gK
	F7QrhPa409hK1W6wSgglU/QdAM4UIOafP6cVbbNvtnK5Ggrtj9bAb50g2EuHRKBInEB/AZJhblr8T
	+X3TYCAA321TvPcbgoK/VGMvtR+MNlSGRN/iiruOBmP4YE6YKTpssOqdZ7kY0nyWAcss=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: add generic treewalk function
Message-Id: <E1oq7Yf-0008NI-Gx@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:49:05 +0000

commit d816b470e0225f2018d011a92e0ebb03595a9085
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d7c5d19bc27492360196e7dad2b227908564fff)
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 006af15765..c3b2a42214 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1731,6 +1731,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2103,18 +2232,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2170,7 +2287,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 5abf06c21c..fc9882ac37 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -167,6 +167,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -278,6 +279,45 @@ int do_tdb_delete(struct connection *conn, TDB_DATA *key,
 
 void conn_free_buffered_data(struct connection *conn);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:49:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:49:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435537.688977 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Yq-0008L8-D5; Wed, 02 Nov 2022 06:49:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435537.688977; Wed, 02 Nov 2022 06:49:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Yq-0008L0-AS; Wed, 02 Nov 2022 06:49:16 +0000
Received: by outflank-mailman (input) for mailman id 435537;
 Wed, 02 Nov 2022 06:49:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yp-0008Ko-LC
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yp-000318-KX
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yp-0008Nw-Js
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=fNa40jI0K7bw/SdrDPJIwVjM4NQIum+PYKv2EYzhTMg=; b=t2FMSsdhWeZFiU3MEwv0L5K0rH
	aeSnnvIFIvbj0Cs8wxwLX7cTGLE9SSH06SHJTfHRq7YzjCoqD4JEyKIDVoTUmTGc0GiWcyF4qAZaj
	JxC/Y5c7FvdulUQh1Fv33UxGKs/NIUi90+hWd3iTrV2q9SP3cip+22E3tfUUOAdzs0uk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: simplify check_store()
Message-Id: <E1oq7Yp-0008Nw-Js@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:49:15 +0000

commit ba1cff4b1be983ea7ec55a994a3adc8b40903800
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 70f719f52a220bc5bc987e4dd28e14a7039a176b)
---
 tools/xenstore/xenstored_core.c | 43 ++++++++++++++---------------------------
 1 file changed, 15 insertions(+), 28 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c3b2a42214..877e88560c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2275,46 +2275,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2324,19 +2312,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:49:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:49:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435539.688982 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Z0-0008ON-En; Wed, 02 Nov 2022 06:49:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435539.688982; Wed, 02 Nov 2022 06:49:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Z0-0008OF-C1; Wed, 02 Nov 2022 06:49:26 +0000
Received: by outflank-mailman (input) for mailman id 435539;
 Wed, 02 Nov 2022 06:49:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yz-0008O6-OU
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yz-00031D-Nf
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Yz-0008OP-Mv
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8OkfY+TL5k068kYP+tKWKkd33KyYDMVWuqEaJrZYLuI=; b=Yono4hYY8MvltBgXmMg8TOr7pg
	La/qrBV17VU8ovYRBD4opRcV7yR+wBtRJXBuWTxnl52/H2V1TtMBrZycmbRsLlE80hjfloTcpMGZi
	ziil++NrEl1bwYiCIFuZI185QQ67c2Od/U4TZNhv7ta8ddH+7kNs+UEAMPvBCZNXf3Do=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: use treewalk for check_store()
Message-Id: <E1oq7Yz-0008OP-Mv@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:49:25 +0000

commit 1cfbd2567b68e3e021a963d6f45f6adfa359c8d4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 877e88560c..fb25f72017 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2242,18 +2242,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2267,70 +2255,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
-
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
+	struct hashtable *reachable = arg;
 
-			childnode = read_node(NULL, childname, childname);
-
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2379,24 +2326,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char * root = talloc_strdup(NULL, "/");
-	struct hashtable * reachable =
-		create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
+
+	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
 		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:49:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:49:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435540.688986 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7ZA-0008Re-He; Wed, 02 Nov 2022 06:49:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435540.688986; Wed, 02 Nov 2022 06:49:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7ZA-0008RW-F1; Wed, 02 Nov 2022 06:49:36 +0000
Received: by outflank-mailman (input) for mailman id 435540;
 Wed, 02 Nov 2022 06:49:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Z9-0008RM-Ro
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Z9-00031H-Qh
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Z9-0008Oo-Q0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=LsJ75yU93ESpKuWoBvfuNx3Y7Fxp/tUy+3HwqJNt00A=; b=SlflKESI8bCeCQp+Jd/wliASSc
	M6XUEHxQBBkvnjC13zGv+eB+QnhDkb6QPLn302uxba80nM1Usoi5vxz+QkFsSXGjutsxKkcz4sZwt
	APyC5QDUnKNtDIxPz5/ZICl2T8Bqi0kdteQbNDMlNBmYq0DfLqz/5k/1gWFtfV3GLnwQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1oq7Z9-0008Oo-Q0@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:49:35 +0000

commit 8c8a5b3905d4bd6d2646ddaf00a424bde62289ef
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ea16962053a6849a6e7cada549ba7f8c586d85c6)
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index fb25f72017..9655af4c01 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1231,21 +1231,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1514,69 +1499,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1584,9 +1559,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1621,7 +1608,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:49:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:49:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435541.688990 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7ZK-0008UU-JW; Wed, 02 Nov 2022 06:49:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435541.688990; Wed, 02 Nov 2022 06:49:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7ZK-0008UM-Gh; Wed, 02 Nov 2022 06:49:46 +0000
Received: by outflank-mailman (input) for mailman id 435541;
 Wed, 02 Nov 2022 06:49:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7ZJ-0008UB-UY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7ZJ-00031h-Tp
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7ZJ-0008PD-TA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=158cDhiQ81EilJl54kLcmkOMrdVsAsgUptfOjxEWj8g=; b=D1v66Un7ns/5omtOxPZxXZ2LzR
	VDNKPcGtspXsLeftmFpZncyrGEzKEqe2mUjoKXL26HxWF+BDbOk9BbE4VdgG7CZxPegWHNiHrl1EF
	INW4Ki7Wcq8YLYKB3ufdAPOWcO5ArvscmdH/22i90NOdkEu5tVWo7O+MdWuedbrKslj4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1oq7ZJ-0008PD-TA@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:49:45 +0000

commit a8922c661c2e2436c0d60da3ab9b12b47f308a92
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 755d3f9debf8879448211fffb018f556136f6a79)
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 85 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 81 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9655af4c01..7eb698e1fc 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -76,6 +76,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -662,7 +663,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -705,7 +706,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1546,7 +1547,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1608,7 +1609,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2461,6 +2462,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2484,6 +2487,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 	{ NULL, 0, NULL, 0 } };
@@ -2558,7 +2562,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2594,6 +2598,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index fc9882ac37..ec24c27ac2 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -204,6 +204,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(void);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 void check_store(void);
@@ -242,6 +245,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 43fc2c4879..116b78c0f6 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -204,10 +204,65 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		key.dptr = (char *)node->name;
+		key.dsize = strlen(node->name);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -842,15 +897,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -911,23 +966,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -945,15 +988,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1072,7 +1115,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index bab405209e..5bd253395d 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,7 +64,7 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:49:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:49:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435542.688994 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7ZU-00005W-L6; Wed, 02 Nov 2022 06:49:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435542.688994; Wed, 02 Nov 2022 06:49:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7ZU-00005O-IK; Wed, 02 Nov 2022 06:49:56 +0000
Received: by outflank-mailman (input) for mailman id 435542;
 Wed, 02 Nov 2022 06:49:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7ZU-00005E-1D
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7ZU-00031l-0Y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7ZT-0008Pf-W2
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:49:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=MTusiPps55Lv/45CllhUUVKwUbD7XPLoeiv9/Vj+pT4=; b=csTRJ2HHvT25w9Pdk9u1z7GCJB
	8tJHOySo3iMLeXdWyT7RVrh93c7LJDae8rUqAXOjyDnS9fs8qaJsjK/dYRf20r0arnAOPRWrT+DrG
	m+G0GQCobjnjtMQKZmjN5+h3dbyhApt1B8P5RgTMp7qYLZIBFcmZBxnpl7taGLhJh2B8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: make the internal memory data base the default
Message-Id: <E1oq7ZT-0008Pf-W2@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:49:55 +0000

commit 145871612f70aefd433c5933bc9ebe5dfb888138
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d174fefa90487ddd25ebc618028f67b2e8a1f795)
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index adb8408b63..b4d7ed573e 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -128,9 +128,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom = xc_dom_allocate(xch, cmdline, NULL);
     rv = xc_dom_kernel_file(dom, kernel);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 7eb698e1fc..683554ff2c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2132,7 +2132,7 @@ static void accept_connection(int sock, bool canwrite)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2461,7 +2461,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2486,7 +2487,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2562,7 +2563,8 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:Q:q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2596,7 +2598,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:50:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:50:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435543.688998 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Ze-0000w5-Mk; Wed, 02 Nov 2022 06:50:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435543.688998; Wed, 02 Nov 2022 06:50:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Ze-0000vx-Jz; Wed, 02 Nov 2022 06:50:06 +0000
Received: by outflank-mailman (input) for mailman id 435543;
 Wed, 02 Nov 2022 06:50:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ze-0000rH-47
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:06 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ze-000329-3M
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:06 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Ze-0008QI-2l
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5avgxjcmhF+3t8ors//+upZa1i+IGAJzXmrMe7UHwNU=; b=0ylhg44RfgR2t6TY/nFMt6E/WJ
	ODKExwifHH8hEwJPv9AzcGIG0dwe9/7ZsBPY7OpXpCvXqcz9b/gQazKNy8OrO+4JEu6xntERp3dhv
	gAWTXR0i2JLShE/OFj77yCUt0LQmJqcDP8rNm/dccdv0KmH16QcnSAmjCJiWGc6MACr8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] docs: enhance xenstore.txt with permissions description
Message-Id: <E1oq7Ze-0008QI-2l@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:50:06 +0000

commit 3545d0f15efce1c053473019ea893799c13d1275
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d084d2c6dff7044956ebdf83a259ad6081a1d921)
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 0dbac442d7..d5084bcbaa 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:50:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:50:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435544.689002 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Zo-0000zN-Pp; Wed, 02 Nov 2022 06:50:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435544.689002; Wed, 02 Nov 2022 06:50:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Zo-0000zE-N1; Wed, 02 Nov 2022 06:50:16 +0000
Received: by outflank-mailman (input) for mailman id 435544;
 Wed, 02 Nov 2022 06:50:16 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Zo-0000z7-7T
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:16 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Zo-00032E-6j
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:16 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Zo-0008Qn-5g
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:16 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=WhMioCBbjyXjqfuEZM1oDKDjDSK+wR1LWL94/BQInaw=; b=ozjTfQ660PBH4L1AyvUQzXGqJ6
	tLuaL0fiY/iVRqsTAlEEBA5EI+rL5ZoNbSgeVoRQcp0QFTFQOdTRIz8K7iVkJuMENYYkyg53ecuLd
	eQAMm5NVFaedHdwh2in44aVvJpAHMiHafivmvSonzVT54IGFFUIlFd0JoJWO8rC3YLe4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1oq7Zo-0008Qn-5g@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:50:16 +0000

commit 94b2f97eaae17f3c49816c2f7224d5b698d28287
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit db471408edd46af403b8bd44d180a928ad7fbb80)
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 328d3a5198..d82764f60f 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -89,10 +89,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; List.iter (recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = List.rev_map walk node.children |> List.rev }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			List.rev_map walk node.children |> List.filter is_valid |> List.rev } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -446,11 +457,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:50:27 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:50:27 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435545.689006 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Zz-00012B-RF; Wed, 02 Nov 2022 06:50:27 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435545.689006; Wed, 02 Nov 2022 06:50:27 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7Zz-000123-OZ; Wed, 02 Nov 2022 06:50:27 +0000
Received: by outflank-mailman (input) for mailman id 435545;
 Wed, 02 Nov 2022 06:50:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Zy-00011t-Ae
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Zy-00032I-9q
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:26 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7Zy-0008RC-92
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:26 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ItjkoR6MSsuCvAGfEQljgRlVEiCXw9TU/mYqZh7FFC0=; b=2QGpqDIBeMQntjy8bKh7q2BWJW
	xLMW1kuLT2PQWvD5fqZzLJu9D7LcUZeCDWH6IZnlNsXH6pLVpjNKVVu9QzDYVuF9lN7KvdHYkc0Be
	G7CRlIergxo0vr64QFNztozQcZ9bCUsED2YKOOdvnetnyXyznD1q1DqJZoe6BFMLutFM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1oq7Zy-0008RC-92@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:50:26 +0000

commit 29506319c6cefb370bafc20689b67a4a3523197e
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3)
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index d2a3ba064e..027252ece8 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -587,7 +587,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:50:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:50:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435546.689011 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7a9-00014y-UH; Wed, 02 Nov 2022 06:50:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435546.689011; Wed, 02 Nov 2022 06:50:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7a9-00014q-Q6; Wed, 02 Nov 2022 06:50:37 +0000
Received: by outflank-mailman (input) for mailman id 435546;
 Wed, 02 Nov 2022 06:50:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7a8-00014Y-DK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7a8-00032M-Ca
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7a8-0008Ri-By
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Uq0AwSWGGWl1y2CKqGwGsoqfvJxBkf1G0QJHDGA/2UA=; b=d32QPp23xd/ysl6aobsyx1Qbiz
	K4ISK2e5Rsmpi+MgjIFMsKuUfDrFDHLFZaPaoydm0wkK+1TQ34IbkQ23wik1W4sN6di+ZqokGuJeP
	smeBH05q741aL+jNyYxeVP/Gg2sXSEkdGg1L/cdEJiOEeenqlioTvRLCWKpGDyTq2WAA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: fix deleting node in transaction
Message-Id: <E1oq7a8-0008Ri-By@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:50:36 +0000

commit 30a293fba36b438d90b802132d70020e76086058
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187)
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd592845e7..6297149986 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -424,7 +424,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 06:50:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 06:50:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435547.689014 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7aJ-00017u-UV; Wed, 02 Nov 2022 06:50:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435547.689014; Wed, 02 Nov 2022 06:50:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq7aJ-00017m-Rm; Wed, 02 Nov 2022 06:50:47 +0000
Received: by outflank-mailman (input) for mailman id 435547;
 Wed, 02 Nov 2022 06:50:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7aI-00017Z-GJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7aI-00032i-Fb
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq7aI-0008S7-En
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 06:50:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=jSGo+W3grDr1mPPJbXVK+2woEpe8HbYzlnYMgzGAyU4=; b=Cmq51gtgzsT5dr6c1o1zO3o+2I
	6+54QHLKc8DrZI4c8L+5Qymhq1XVnJXYEZ21JuXp1r2b59M9Xz26FEpgcTF4WMlCAnuG7Uj87tCNQ
	TcjHpwlZaOVDZpvQDK7p/0XlzyDja1A+s+AgZhrzc3FEGxSSjTBvlWpnmSf57zpeWaP4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1oq7aI-0008S7-En@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 06:50:46 +0000

commit 377dbf9cea55a1976d0957c1f209b083c734c250
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:25:15 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff)
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 683554ff2c..1648a7ccf5 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -632,8 +632,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -746,10 +745,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6297149986..5e4780e874 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -205,25 +206,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -246,7 +242,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -265,10 +260,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -279,9 +270,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -308,7 +300,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -327,7 +319,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -339,7 +331,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -377,100 +368,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -560,6 +541,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -581,13 +563,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -661,7 +647,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -673,11 +659,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:22:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:22:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435571.689052 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq90d-0006QJ-Np; Wed, 02 Nov 2022 08:22:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435571.689052; Wed, 02 Nov 2022 08:22:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq90d-0006QB-Ki; Wed, 02 Nov 2022 08:22:03 +0000
Received: by outflank-mailman (input) for mailman id 435571;
 Wed, 02 Nov 2022 08:22:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90c-0006Q5-O0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90c-00057r-NI
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90c-0006Ns-MH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Lrlk6nQyVMSRRNCuFx7Q9vraveJzLiV2R74mYi3wClg=; b=bffCxvr/r/Qgq76wuq6nS3zZHD
	Iqp3iQn2dKvknzTl9rajHO80pzbQf1oqs8x776+gYgLaA3zVmI1S9WLgZYOKmSVSAbpD69wbfbdya
	tNjycOFR7SwVSZXkS/jVeNUgpcgeyh9C53JOLis8wYSYXVJ9Vz/QjWIhwlmToxFi0Loc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1oq90c-0006Ns-MH@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:22:02 +0000

commit d0dd461bfc8dd25b94dcf72bc5f79a4b362e7f03
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 1cd3cc7ea27cda7640a8d895e09617b61c265697)
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 1d05d25a48..6afe8cb59d 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -977,9 +977,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -990,7 +989,7 @@ static int destroy_node(void *_node)
 
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -999,7 +998,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1021,23 +1021,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:22:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:22:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435572.689055 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq90n-0006T1-Qr; Wed, 02 Nov 2022 08:22:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435572.689055; Wed, 02 Nov 2022 08:22:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq90n-0006St-Nw; Wed, 02 Nov 2022 08:22:13 +0000
Received: by outflank-mailman (input) for mailman id 435572;
 Wed, 02 Nov 2022 08:22:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90m-0006Sn-Rb
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90m-000581-Qs
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90m-0006OR-Pp
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sz6vo2JpsxKqM4vCDgyVuuehGUrnsiNO4WtqljHP5FI=; b=0SuUavaptgrKkrVCew7V3+pVBC
	FDh619K9Ergdb6oghDdaw/IOa58Q4iHjqSW0love0/cwDuZJcqWt8hWgTxhZE/sVuuze/xOoz9sWD
	45yAT/oyVJ4C2yx5tky6L24fJujGSd4CJA3IGHRQ92iFZieNa/p5v16gIXuCtqENy0W0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1oq90m-0006OR-Pp@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:22:12 +0000

commit bd50953ef300049cc2d20fdc5a34b90a97b6abc0
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    (cherry picked from commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34)
---
 tools/xenstore/xenstored_core.c        | 25 +++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 6afe8cb59d..8e91b55498 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -468,15 +468,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
@@ -979,18 +981,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	key.dptr = (void *)node->name;
-	key.dsize = strlen(node->name);
-
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 196a6fd2b0..9369c4cbfd 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -119,6 +119,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 2881f3b2e4..4ffa183111 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -582,6 +582,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:22:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:22:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435573.689059 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq90x-0006Va-SE; Wed, 02 Nov 2022 08:22:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435573.689059; Wed, 02 Nov 2022 08:22:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq90x-0006VS-PV; Wed, 02 Nov 2022 08:22:23 +0000
Received: by outflank-mailman (input) for mailman id 435573;
 Wed, 02 Nov 2022 08:22:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90w-0006VE-Vq
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90w-00058H-UK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq90w-0006Ou-TO
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=H4IQL0l/p4whJIHesqotxc4prCaxuztALbY83sOpFY8=; b=fvlwMfi6q5/aO+ytUP4iXx0iVo
	adcc9Xz8Im+ADEEwYtvoeVW6aQYjwz/8ZKxjvGYqKADt6bD3wwsOE2a/lD1/UsEnPLn9W/i+lkeW3
	PN1cu+01lqwwL66axZG0R+iyLZnD9/f0PopsexeNyE4eib+ebDCIBVSu83ktEtel0r8M=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: split up send_reply()
Message-Id: <E1oq90w-0006Ou-TO@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:22:22 +0000

commit 00240cfc5e33b762850dfe16be501341b1fc5ca1
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32)
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 42 +++++++----------------
 3 files changed, 58 insertions(+), 59 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8e91b55498..e6776bae8f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -674,49 +674,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -724,8 +707,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 9369c4cbfd..2b0f796d9b 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -150,6 +150,7 @@ unsigned int get_strings(struct buffered_data *data,
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 9ff20690c0..6d8097376e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -72,37 +72,17 @@ static bool is_child(const char *child, const char *parent)
 	return child[len] == '/' || child[len] == '\0';
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
+static const char *get_watch_path(const struct watch *watch, const char *name)
 {
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
+	const char *path = name;
 
 	if (watch->relative_path) {
-		name += strlen(watch->relative_path);
-		if (*name == '/') /* Could be "" */
-			name++;
+		path += strlen(watch->relative_path);
+		if (*path == '/') /* Could be "" */
+			path++;
 	}
 
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
+	return path;
 }
 
 /*
@@ -181,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -252,7 +236,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:22:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:22:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435574.689063 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq917-0006YU-Tl; Wed, 02 Nov 2022 08:22:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435574.689063; Wed, 02 Nov 2022 08:22:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq917-0006YL-Qy; Wed, 02 Nov 2022 08:22:33 +0000
Received: by outflank-mailman (input) for mailman id 435574;
 Wed, 02 Nov 2022 08:22:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq917-0006YB-2F
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq917-00058Z-1B
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:33 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq917-0006PL-0O
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:33 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=KEo87xghqN1UGMlS76Y+xBOYZ98zBIlsexOe4JMg1JM=; b=N57YWiIfsJBUNtrf/8BOdK27aK
	E3hX1XjOrTwY01bSCS4eOecNZQ0JLd3ZeCXQYpfU7RLJGNsk7Xc/WfoAWH3+O0mTdL0d76pYIfrhf
	DgmV+sOpUZt5tzcvyvp2pbe3h283QplSUYdkWWHrczMBg8xOEt0YHoqlsqsqdrKYtwGY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1oq917-0006PL-0O@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:22:33 +0000

commit 3530aa6aca01fdffdc9e4af18d4278d169458e60
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ead062a68a9c201a95488e84750a70a107f7b317)
---
 tools/xenstore/xenstored_core.c   | 26 +++++++++++++++++---------
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c |  7 +------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e6776bae8f..5d54779d40 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -208,6 +208,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -251,8 +266,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
@@ -1391,18 +1405,12 @@ static struct {
  */
 static void ignore_connection(struct connection *conn)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored\n", conn);
 
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2b0f796d9b..83d49693fc 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -226,6 +226,8 @@ extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
 
+void conn_free_buffered_data(struct connection *conn);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index d5e1e3e9d4..3bff322d02 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -402,15 +402,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:22:44 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:22:44 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435575.689067 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91H-0006b8-VQ; Wed, 02 Nov 2022 08:22:43 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435575.689067; Wed, 02 Nov 2022 08:22:43 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91H-0006b0-SW; Wed, 02 Nov 2022 08:22:43 +0000
Received: by outflank-mailman (input) for mailman id 435575;
 Wed, 02 Nov 2022 08:22:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91H-0006ar-53
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91H-00058j-4I
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91H-0006Po-3Y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=lh2mBU7PQZbGHm3Z7TP+XFehWPYDpVNoqRM1j0DzzxU=; b=Og0ufpfOgj3dmiMz6cXO3Xrw6a
	wDEPWBpFSFHjTw/5xkrGoSCOlOBbMB3alOrCLOEyE5pWsMzXteIQE7F6OrCYBQ39c1hE/MaRpX0g8
	XsAQsT5bloglIc32VYS+yAsTxhzUOyu29bOhAJG3qyGTn66FvfPPWdOljC4B/Ef2CkWU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: reduce number of watch events
Message-Id: <E1oq91H-0006Po-3Y@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:22:43 +0000

commit a03e2a386e3db9c2df6e24bfd3a44f52f09ca8a5
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297)
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5d54779d40..53d003aebf 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1182,7 +1182,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1194,7 +1194,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1206,7 +1206,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1232,13 +1237,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 4ffa183111..6fbdb29dcd 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -329,6 +333,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -383,15 +410,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 6d8097376e..2f9367767e 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:22:54 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:22:54 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435576.689070 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91S-0006eN-29; Wed, 02 Nov 2022 08:22:54 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435576.689070; Wed, 02 Nov 2022 08:22:54 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91R-0006eB-VT; Wed, 02 Nov 2022 08:22:53 +0000
Received: by outflank-mailman (input) for mailman id 435576;
 Wed, 02 Nov 2022 08:22:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91R-0006dz-8W
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91R-000599-7j
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91R-0006QH-6o
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:22:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Y69l6YK2kVXV6Fpx8Ax5CW9wTpKGElSz8JF2YT3Xr3g=; b=ZR6OISd2RJ81NwnSjBan0p7c6b
	t9rcqpaCOg1ZF04KNFEUeaN8e1JS+/Hgpj6NBAADhb8riJyNzdPBF6GNRO2Hio05oTg1NntyD03pw
	mgNt8nR6C4P7RAmzfCFQDL+g1u2YF+Pp4IgoNKnZSJqsCkluL5kMssGIGT0ipRYrUCjg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: let unread watch events time out
Message-Id: <E1oq91R-0006QH-6o@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:22:53 +0000

commit 36ed7fe5da0eb8554e94718fb6599795cdef21d0
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 5285dcb1a5c01695c11e6397c95d906b5e765c98)
---
 tools/xenstore/xenstored_core.c | 127 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 53d003aebf..98837ef2e9 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -106,6 +106,8 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -208,19 +210,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -333,6 +408,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *p_ro_sock_pollfd_idx,
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -354,10 +430,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *p_ro_sock_pollfd_idx,
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (domain_can_read(conn) ||
 			    (domain_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -701,6 +779,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -752,6 +831,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -1994,6 +2079,9 @@ static void usage(void)
 "  -W, --watch-nb <nb>     limit the number of watches per domain,\n"
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2015,6 +2103,7 @@ static struct option options[] = {
 	{ "trace-file", 1, NULL, 'T' },
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2026,6 +2115,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2037,7 +2159,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2082,6 +2204,9 @@ int main(int argc, char *argv[])
 		case 'A':
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 83d49693fc..3112c11811 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <dirent.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -56,6 +57,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -88,6 +91,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -199,6 +203,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:23:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:23:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435578.689075 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91d-0006hS-44; Wed, 02 Nov 2022 08:23:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435578.689075; Wed, 02 Nov 2022 08:23:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91d-0006hK-0z; Wed, 02 Nov 2022 08:23:05 +0000
Received: by outflank-mailman (input) for mailman id 435578;
 Wed, 02 Nov 2022 08:23:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91b-0006h6-Bl
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91b-00059Z-B1
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91b-0006Qy-AF
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=/in7xDK1wUkNugk1Wn7XDs3KjdTM5fWVQSYxPJhE0Zs=; b=iUt1sdAb3hwwsS1cjP0HGd7zL9
	2VCYWV10LSQ7rs4duRgYeRtwZctNT/EWVMIyhizwGeExf5ORKNWklp1Y5vyLprH1WOc0B1NJiC+iQ
	/46/DZoScWgHcQuZEUrLZAOFte6io1TakdrHRTgD6LUul3TQqFn67MN2Rpk48YDWsfMU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: limit outstanding requests
Message-Id: <E1oq91b-0006Qy-AF@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:23:03 +0000

commit 3dafa5a77440325a51dfbd75a297febc618bb24a
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 36de433a273f55d614c83b89c9a8972287a1e475)
---
 tools/xenstore/xenstored_core.c   | 78 ++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h   | 20 +++++++++-
 tools/xenstore/xenstored_domain.c | 37 ++++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 ++++++--
 5 files changed, 141 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 98837ef2e9..2ed91d1329 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -105,6 +105,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -220,12 +221,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -241,6 +254,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -349,6 +386,7 @@ static bool write_messages(struct connection *conn)
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -362,6 +400,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -800,6 +843,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -807,7 +852,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -837,8 +883,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1574,6 +1625,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1644,6 +1696,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
 	new->is_ignored = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 
@@ -2079,6 +2132,9 @@ static void usage(void)
 "  -W, --watch-nb <nb>     limit the number of watches per domain,\n"
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2103,6 +2159,7 @@ static struct option options[] = {
 	{ "trace-file", 1, NULL, 'T' },
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2148,6 +2205,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2159,7 +2230,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2204,6 +2275,9 @@ int main(int argc, char *argv[])
 		case 'A':
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 3112c11811..edeaa96dd1 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -45,6 +45,8 @@ typedef int32_t wrl_creditt;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -52,6 +54,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -93,6 +106,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -154,7 +170,8 @@ unsigned int get_strings(struct buffered_data *data,
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -202,6 +219,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 3bff322d02..2dd80eb1a7 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -82,6 +82,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -284,8 +287,12 @@ bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	if (conn->is_ignored)
 		return false;
@@ -334,7 +341,7 @@ static struct domain *alloc_domain(void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -383,8 +390,6 @@ static int new_domain(struct domain *domain, int port)
 	domain->conn->id = domain->domid;
 
 	domain->remote_port = port;
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
 
 	return 0;
 }
@@ -922,6 +927,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5e00087206..4bff2e655b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -67,6 +67,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 2f9367767e..c50c0575f0 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -238,8 +241,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	talloc_set_destructor(watch, destroy_watch);
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:23:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:23:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435579.689080 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91n-0006k2-67; Wed, 02 Nov 2022 08:23:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435579.689080; Wed, 02 Nov 2022 08:23:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91n-0006ju-2k; Wed, 02 Nov 2022 08:23:15 +0000
Received: by outflank-mailman (input) for mailman id 435579;
 Wed, 02 Nov 2022 08:23:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91l-0006jZ-Hb
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91l-00059k-Gx
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91l-0006RP-DW
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sY8UFWHkyXOu1uhK7WpkW7EEVgB4h2cglmH7y5kyXZo=; b=MVXzoCxYFvSu91qIGeK4O3Xn/D
	bblccTiEF6e2OLHo/4TG+65Yx28V0YLa4taJaHkpAE/AGEc9FPLSLojZpJdYgRCyGwKuBsxnhG8sI
	OtUTeLaU3kzkpAVdH68oYEwP1/onGkOc1IfGv4Wcm926F3FpGo2S1t+fwIbiykK9/9bA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1oq91l-0006RP-DW@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:23:13 +0000

commit 83b9da9282488bfadaf322a592805b4421d9b60b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2)
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2ed91d1329..c6f1d4189c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -823,6 +823,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -855,7 +856,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -877,12 +878,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index edeaa96dd1..1eb6131fc8 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -51,6 +51,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:23:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:23:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435580.689082 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91x-0006nr-99; Wed, 02 Nov 2022 08:23:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435580.689082; Wed, 02 Nov 2022 08:23:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq91x-0006nj-6R; Wed, 02 Nov 2022 08:23:25 +0000
Received: by outflank-mailman (input) for mailman id 435580;
 Wed, 02 Nov 2022 08:23:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91v-0006nS-Kh
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:23 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91v-00059v-Jy
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:23 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq91v-0006Ru-JH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:23 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=f3seQqkqFFO/ehOXTFmjtwf8TpBWkQVb3Ms/7r2iT+4=; b=6MpzQwpkwWGq+ROdV92xn0eS8N
	GYHPoCxGEKwHM0h+mmDQVYWsTZ04Px7z8y5mxrElHs312c/DhxhAie12fH26rA8zIwWhUzrCXf+0j
	H5LpzGsg/jUnsHKTWyaDPrkPfcOJv5z1PRiFZcYPN7E14xy6D67z8Fry2GHiZY2Oq6EI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: fix connection->id usage
Message-Id: <E1oq91v-0006Ru-JH@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:23:23 +0000

commit 9ad9fde555b6ec98c2cec05e28d3ee4c3127d6f5
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831)
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 8d48ab4820..bce6662f6e 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -198,7 +198,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	int cmd;
 	char **vec;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	num = xs_count_strings(in->buffer, in->used);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1eb6131fc8..98db4afcaa 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -93,7 +93,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this a read-only connection? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6fbdb29dcd..9bef6e72a5 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -483,7 +483,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:23:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:23:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435582.689087 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq927-0006qY-Ay; Wed, 02 Nov 2022 08:23:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435582.689087; Wed, 02 Nov 2022 08:23:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq927-0006qQ-80; Wed, 02 Nov 2022 08:23:35 +0000
Received: by outflank-mailman (input) for mailman id 435582;
 Wed, 02 Nov 2022 08:23:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq925-0006q7-Nl
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq925-0005A5-N2
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:33 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq925-0006SP-ML
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:33 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=TjX3Hef/f8LXWSwuypSoJC1I46YtD6Jm4aDRqvGKCog=; b=jlV/ogfcSvHgWyZCrchEG5ZXLr
	Qk1A+fFu03bY9DbX+AoYv7pgE+aEEVsjXoE+VUXDxnwu++hrCCo7+Y9E5gnRwt7NOUy3Txu/VbC6d
	fmxA9Xtdkdz8r4K/5XjaJuBMkpNTaarLNDffCWDtwjE32Wm/plSQQEd31Gbl4I8C3vrs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1oq925-0006SP-ML@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:23:33 +0000

commit 82dfb67578243a1abda3774df0dfd511bdff0572
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit dbef1f7482894c572d90cd73d99ed689c891e863)
---
 tools/xenstore/xenstored_control.c     |   1 +
 tools/xenstore/xenstored_core.c        |  39 +++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 5 files changed, 107 insertions(+), 50 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index bce6662f6e..ab0794deed 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -25,6 +25,7 @@
 #include "talloc.h"
 #include "xenstored_core.h"
 #include "xenstored_control.h"
+#include "xenstored_domain.h"
 
 struct cmd_s {
 	char *cmd;
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c6f1d4189c..12d013d249 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -545,7 +545,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -567,7 +567,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1161,13 +1161,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1217,8 +1221,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1499,10 +1507,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
 
-	if (write_node(conn, node, false))
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
+
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 2dd80eb1a7..306e12358b 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -358,6 +359,18 @@ static struct domain *alloc_domain(void *context, unsigned int domid)
 	return domain;
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port)
 {
 	int rc;
@@ -767,30 +780,28 @@ void domain_init(void)
 	virq_port = rc;
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -826,7 +837,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -836,8 +847,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -856,25 +873,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -884,13 +901,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4bff2e655b..4edf1dba94 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -57,10 +57,10 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 9bef6e72a5..bf2fda8234 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -523,8 +523,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:23:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:23:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435583.689091 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92H-0006tC-CQ; Wed, 02 Nov 2022 08:23:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435583.689091; Wed, 02 Nov 2022 08:23:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92H-0006t4-9l; Wed, 02 Nov 2022 08:23:45 +0000
Received: by outflank-mailman (input) for mailman id 435583;
 Wed, 02 Nov 2022 08:23:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92F-0006st-Qx
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92F-0005AN-QA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92F-0006Sw-PV
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=gNoBD1UqrBU1AvPXS/Qpyus/7rtABgxM3lXJzvECzcQ=; b=ih/N6xgyJ6wUCmSBMpBbyvsBYh
	jPmRPT9xWyBQEqCubdrHlOi9mK9GhIBsq9YBUsrqChSi1I9k8GVDLTAz6glL3a08anmAOP/lsTbB+
	Rlhkigg2kyvfSnIRIis5q+noXSH8S9jxoU3CiNU2ZBonkLJ0NQA/hPT/gC9+4c3u91Co=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1oq92F-0006Sw-PV@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:23:43 +0000

commit 93a9c3a066193e21763c84e04fbe56902bcb5c07
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 268369d8e322d227a74a899009c5748d7b0ea142)
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index cc7dfc8c64..34db3b7847 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -59,4 +59,8 @@
     })
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 12d013d249..ff649b7544 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -105,6 +105,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
@@ -502,6 +503,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -523,14 +525,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -545,19 +546,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -672,7 +690,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -735,7 +753,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1117,7 +1135,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1396,7 +1414,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1424,7 +1442,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2177,6 +2195,8 @@ static void usage(void)
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2258,6 +2278,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 98db4afcaa..7e371253d2 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -34,6 +34,7 @@
 #include "list.h"
 #include "tdb.h"
 #include "hashtable.h"
+#include "utils.h"
 
 /* DEFAULT_BUFFER_SIZE should be large enough for each errno string. */
 #define DEFAULT_BUFFER_SIZE 16
@@ -223,6 +224,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index bf2fda8234..778b7e439c 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -266,6 +269,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -303,6 +311,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:23:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:23:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435584.689095 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92R-0006vl-Eq; Wed, 02 Nov 2022 08:23:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435584.689095; Wed, 02 Nov 2022 08:23:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92R-0006vc-BO; Wed, 02 Nov 2022 08:23:55 +0000
Received: by outflank-mailman (input) for mailman id 435584;
 Wed, 02 Nov 2022 08:23:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92P-0006vN-U0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92P-0005Aq-TK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92P-0006Us-Sb
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:23:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=X+0MeQESOYmRWbzzm9NEFJqyxV0GbYCuu+qQ7pTn9fI=; b=ivOrS/2XapA0H8JFAFG8Qsqce1
	J5sjQOJk2ICnntGQZDiNPGV+8dOzUiSLCvb4CykLRTKj5VPRTUxPzOcHjQdJOFOYOjGyGrgdhwakF
	em/KAeT13v/qAy4zy3YxBAcJrj7I7OJ4cSwEv9/5Wli5OQIum5RzZAYxrA+azAy7TIuI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1oq92P-0006Us-Sb@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:23:53 +0000

commit 0406917f364d170eae6e25ab3e9314e27db2c790
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 60e2f6020dea7f616857b8fc1141b1c085d88761)
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 2 ++
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ff649b7544..8123a65a58 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1834,7 +1834,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -1873,7 +1874,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(void)
+void setup_structure(void)
 {
 	char *tdbname;
 	tdbname = talloc_strdup(talloc_autofree_context(), xs_daemon_tdb());
@@ -1891,6 +1892,7 @@ static void setup_structure(void)
 	manual_node("/", "tool");
 	manual_node("/tool", "xenstored");
 	manual_node("/tool/xenstored", NULL);
+	domain_entry_fix(dom0_domid, 3, true);
 
 	check_store();
 }
@@ -2389,9 +2391,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure();
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init)
 		domain_init();
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 7e371253d2..d95e4262a9 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -195,6 +195,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(void);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 void check_store(void);
 void corrupt(struct connection *conn, const char *fmt, ...);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 306e12358b..bed6c4e05a 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -732,6 +732,8 @@ static int dom0_init(void)
 	if (dom0->interface == NULL)
 		return -1;
 
+	setup_structure();
+
 	talloc_steal(dom0->conn, dom0); 
 
 	xenevtchn_notify(xce_handle, dom0->port);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:24:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:24:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435585.689099 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92b-0006za-I5; Wed, 02 Nov 2022 08:24:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435585.689099; Wed, 02 Nov 2022 08:24:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92b-0006zR-Ev; Wed, 02 Nov 2022 08:24:05 +0000
Received: by outflank-mailman (input) for mailman id 435585;
 Wed, 02 Nov 2022 08:24:04 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92a-0006zC-0j
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:04 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92a-0005BG-05
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92Z-0006VQ-Ve
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Al9g0ryXFf7prawnc1MPMjjfnCPC7ZYNaBtijztTkgM=; b=s46GcaPy+f0tcCSslZxMVaKiP0
	iuDQ7riUVoC65wEixRZQdTSB4UNr7s59ERrDD/Oym+oRbzfx6LHC+zsD1LEdeskMsz+6v0nQktxoa
	e6atlRLWUwijY0yS/VCdBmsbFSbv9HeoFfvK1GZFg9JzxFcMqw0fMduEzBxYDKIOYwnk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1oq92Z-0006VQ-Ve@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:24:03 +0000

commit 03889b67169cf973c0e0008a22c5b7cd119f90e9
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d4a8ec7a93faedbe54fd197db146de628459e77)
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8123a65a58..9fd83ea025 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -107,6 +107,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2199,7 +2201,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2225,6 +2234,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2270,7 +2280,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2278,11 +2288,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2297,7 +2312,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2343,7 +2358,10 @@ int main(int argc, char *argv[])
 			quota_nb_perms_per_node = strtol(optarg, NULL, 10);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index d95e4262a9..4e53072e63 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -226,6 +226,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index bed6c4e05a..8daa876588 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -80,6 +80,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -293,6 +300,9 @@ bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	if (conn->is_ignored)
@@ -934,6 +944,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4edf1dba94..3a8c6bab48 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,6 +64,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:24:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:24:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435586.689103 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92l-00072K-JA; Wed, 02 Nov 2022 08:24:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435586.689103; Wed, 02 Nov 2022 08:24:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92l-00072C-GT; Wed, 02 Nov 2022 08:24:15 +0000
Received: by outflank-mailman (input) for mailman id 435586;
 Wed, 02 Nov 2022 08:24:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92k-00071y-4C
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:14 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92k-0005BQ-34
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:14 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92k-0006W4-2O
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:14 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=z0ff9FHypS/lh0iSvyAgD4u1UUggkosNsSP7GbbQZuY=; b=NWcf9BmER3FG/u91XIuppsrjuE
	hVT/GRgBJKIUl5xWi4W0EEwCkxFYZQjMNDMpXTC/L8Ne6WrVzjCkwAYdsiRtMMfFNk+dpHe8q/b5Q
	C692TfD7VsZmxmOrqRQM/XgTuy0UL2Ux1+VcKqAOQ47+BvugPGWq1ZoMQ1+tX3dlANFA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: add memory accounting for responses
Message-Id: <E1oq92k-0006W4-2O@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:24:14 +0000

commit cc289061d93786aa5bd504c91b583e1abb55bbb4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    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 f6d00133643a524d2138c9e3f192bbde719050ba)
---
 tools/xenstore/xenstored_core.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 9fd83ea025..4322d3cf63 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -257,6 +257,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -845,11 +847,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -914,6 +919,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:24:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:24:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435588.689107 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92v-00075g-Ko; Wed, 02 Nov 2022 08:24:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435588.689107; Wed, 02 Nov 2022 08:24:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq92v-00075W-Hx; Wed, 02 Nov 2022 08:24:25 +0000
Received: by outflank-mailman (input) for mailman id 435588;
 Wed, 02 Nov 2022 08:24:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92u-00075L-6g
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92u-0005Bb-5z
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq92u-0006Wb-5M
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=47v3vWvPcdOHXHqGM81hBmrNxh1mE8TLMBrRtRRqhy4=; b=ER6l04WKxJNaUlm8alHh6Hbv21
	OO7NO5JEFpW19kVgbHX9FFirzUR8pZT1ydpWPuKC6KzZZDVXZlzrYsCt9wlG+K+7ic949iXgFYvNP
	bc7+GITv1KPCADewz2hzW8gggTjENc+IljKlQq1SvFNdIKWBAnKm9J52Vbg9P97gteZ4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: add memory accounting for watches
Message-Id: <E1oq92u-0006Wb-5M@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:24:24 +0000

commit 3a7c46a94454aa48f6e247ed91773d96b4b70afb
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    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 7f9978a2cc37aaffab2fb09593bc598c0712a69b)
---
 tools/xenstore/xenstored_core.c  | 1 +
 tools/xenstore/xenstored_watch.c | 7 ++++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 4322d3cf63..0f589a1f63 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -407,6 +407,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index c50c0575f0..7118c30e8c 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -224,7 +224,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 		return ENOMEM;
 	watch->node = talloc_strdup(watch, vec[0]);
 	watch->token = talloc_strdup(watch, vec[1]);
-	if (!watch->node || !watch->token) {
+	if (!watch->node || !watch->token ||
+	    domain_memory_add_chk(conn->id, strlen(vec[0]) + strlen(vec[1]))) {
 		talloc_free(watch);
 		return ENOMEM;
 	}
@@ -265,6 +266,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -280,6 +283,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:24:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:24:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435589.689110 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq935-00078P-ML; Wed, 02 Nov 2022 08:24:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435589.689110; Wed, 02 Nov 2022 08:24:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq935-00078I-JV; Wed, 02 Nov 2022 08:24:35 +0000
Received: by outflank-mailman (input) for mailman id 435589;
 Wed, 02 Nov 2022 08:24:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq934-000785-9i
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq934-0005Bo-91
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq934-0006X2-8T
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=R24z4nBCq1ylNdQ4WPY8hRRXzs+wXJmCcbkasarFfJs=; b=P/G8f2W8NddHG+pOLEoSi7aYn9
	+8IAbchnH4qwVB3o3IN6VLxogCakDgdy6izFzI8IYK/dqyfvkIvUMIQ6iVz1bf5r4cBJGzk9miAjB
	HR0d9Er9AmHVRJmphgZ8h1Gp6vXRfaopGVebgiVNjjQN3kJwzZQn8ZRY/xt7WmeRaZnE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: add memory accounting for nodes
Message-Id: <E1oq934-0006X2-8T@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:24:34 +0000

commit 36812ae518975e2eb40ad14ff0c70dd0ab08bf82
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    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        | 139 ++++++++++++++++++++++++++++++---
 tools/xenstore/xenstored_core.h        |  13 +++
 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 0f589a1f63..6ed1ae2614 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -498,6 +498,117 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *p_ro_sock_pollfd_idx,
 	}
 }
 
+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.
@@ -551,9 +662,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. */
@@ -617,12 +734,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;
 }
 
@@ -1121,7 +1235,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;
 	}
@@ -1184,6 +1298,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;
 
@@ -1192,17 +1307,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);
 
 	/*
@@ -1254,7 +1369,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;
 			}
 		}
@@ -2077,7 +2192,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);
 		}
 	}
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 4e53072e63..521bc80384 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -141,6 +141,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 */
@@ -163,6 +168,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. */
@@ -258,6 +266,11 @@ extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
 
+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);
 
 #endif /* _XENSTORED_CORE_H */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 778b7e439c..c1beb40a3d 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;
 
@@ -292,6 +295,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
@@ -416,11 +421,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;
@@ -431,7 +436,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);
@@ -459,7 +464,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);
@@ -503,6 +508,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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:24:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:24:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435590.689115 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93F-0007Bg-QB; Wed, 02 Nov 2022 08:24:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435590.689115; Wed, 02 Nov 2022 08:24:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93F-0007BY-NF; Wed, 02 Nov 2022 08:24:45 +0000
Received: by outflank-mailman (input) for mailman id 435590;
 Wed, 02 Nov 2022 08:24:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93E-0007BK-Cp
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93E-0005By-C9
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93E-0006XR-BQ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=f81E3j7U78RRzKt/LfgrVq7ePXAUpt0tVVjYe8cUJUY=; b=djRcTrz37c7juzZVc4CIdZic/n
	WBf7ih86y83mOme8o4KmxQ6ZzQ4zIy7pu6zMMvCVilmQ/TzclyDBnTE5aTVmXZfty7D9KqAiOis8P
	2FY4Qbh4VJ9rpStdVx45ujz/509ZiNz/9eBmVxUBQLaQHs9PI+tKB+k4sqKmVNVM5H+Y=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: add exports for quota variables
Message-Id: <E1oq93E-0006XR-BQ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:24:44 +0000

commit 0cc9d66691d029d7df28da5464ab20c3ca299379
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 1da16d5990b5f7752657fca3e948f735177ea9ad)
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 521bc80384..5abf06c21c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -231,6 +231,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index c1beb40a3d..6e29118c80 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static void set_tdb_key(const char *name, TDB_DATA *key)
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 7118c30e8c..19d0fb01b1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:24:54 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:24:54 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435592.689119 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93O-0007ER-Rj; Wed, 02 Nov 2022 08:24:54 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435592.689119; Wed, 02 Nov 2022 08:24:54 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93O-0007EJ-Ox; Wed, 02 Nov 2022 08:24:54 +0000
Received: by outflank-mailman (input) for mailman id 435592;
 Wed, 02 Nov 2022 08:24:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93O-0007EC-G7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93O-0005CP-FP
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93O-0006Xw-Ec
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:24:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=gfhmk24T7qJjEoMV2U0oCCrAExJ77cTcEfD75OQC1aA=; b=eDf7LVdp5oJdr1988ZEc7wvEg0
	zYyx64Tc76zhYL9Hwwvpk+uxdim3R/5BawCxQiafwlVNvhrYj926czbTwaIa6RroEd+pZZFUYSOtk
	viTA2qzkJhe/HIe2uNnZ1AqcxsKh9rjxGLYv48DbX7NsEpO+6hBcsz1cOF2ZCE7I0YJg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1oq93O-0006Xw-Ec@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:24:54 +0000

commit 7c5316d7c7b805a138c718138e81f7218da144c4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 2081f20f55..1f42a377c1 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -329,6 +329,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index ab0794deed..0227a55656 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "utils.h"
@@ -62,6 +63,114 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 #ifdef __MINIOS__
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
@@ -154,6 +263,8 @@ static struct cmd_s cmds[] = {
 	{ "memreport", do_control_memreport, "[<file>]" },
 #endif
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8daa876588..47e8010b34 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -348,6 +349,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 3a8c6bab48..e013a9991c 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -90,6 +90,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:25:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:25:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435593.689123 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93Z-0007I8-TR; Wed, 02 Nov 2022 08:25:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435593.689123; Wed, 02 Nov 2022 08:25:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93Z-0007I0-Qf; Wed, 02 Nov 2022 08:25:05 +0000
Received: by outflank-mailman (input) for mailman id 435593;
 Wed, 02 Nov 2022 08:25:04 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93Y-0007HG-J9
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:04 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93Y-0005Cg-IQ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93Y-0006Yf-Hh
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sybe/fK3L68m7c8mOCOsJihNtiROOlMg6Bx34YSyNyQ=; b=BmpJc6GuzYQ0oxTMz1TQYN0Ej7
	EDJDTETFXFtQYc91Mr//WQLYWhluUo7c1kcUhjQY69932MA9WbWu6ODR5m5eNNGN8IZfVvFd0i4Ex
	97sG6TzyetjHSAO0Te14UaV0yjBKH2r0zyEHKtFrC3sDG4oziUEMggwe7cE+WspOE6+A=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1oq93Y-0006Yf-Hh@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:25:04 +0000

commit 0bc44ec825866c0ef877f0e3bd158fc470191f90
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 84734955d4bf629ba459a74773afcde50a52236f)
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index f574397a4c..96c125a969 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -22,9 +22,9 @@ let xs_daemon_socket_ro = Paths.xen_run_stored ^ "/socket_ro"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:25:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:25:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435594.689127 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93j-0007hO-VB; Wed, 02 Nov 2022 08:25:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435594.689127; Wed, 02 Nov 2022 08:25:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93j-0007hF-SD; Wed, 02 Nov 2022 08:25:15 +0000
Received: by outflank-mailman (input) for mailman id 435594;
 Wed, 02 Nov 2022 08:25:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93i-0007gw-M5
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:14 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93i-0005Cm-LP
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:14 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93i-0006ZE-Kk
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:14 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=KA4arsGgzS+81tQJsqg3QLupj3LIhP58NGi2JFAOAWQ=; b=J4OwpONfKJQWT5mzmAO2frJuoS
	LSIokxGOW2vjavln36hWKx+2/gmXt+wPVKh0rx/SCdW14nfmcM9/RZVlmKrGMdeHEF+qzlakCT/x1
	f3V4jwzgvTPU6laB/yLCtD7zNGokEh26LZ7hFMTMhSCnMSlBowtyz8hc2jHXngKIbtQ8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1oq93i-0006ZE-Kk@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:25:14 +0000

commit f6a5a1d2e34c995a570c9477010c75f3b87a51cd
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    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 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff)
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 3ab09c6ce9..3279b19b1b 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:25:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:25:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435595.689131 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93u-0007k1-0N; Wed, 02 Nov 2022 08:25:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435595.689131; Wed, 02 Nov 2022 08:25:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq93t-0007jt-Tp; Wed, 02 Nov 2022 08:25:25 +0000
Received: by outflank-mailman (input) for mailman id 435595;
 Wed, 02 Nov 2022 08:25:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93s-0007ji-Ox
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93s-0005Cw-OK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq93s-0006Zl-Nl
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=R2L98w9DB5J2FnnO+3HdfYtxv6wnyskFt+KrypskFLE=; b=A67zSKKkKlFwVlkJWMta9tRl20
	jKmv9zK31ZWGb+5jMNfjHyerfa1+X0EySg7LvvSoc3PuA0PixNO+tesBmUES9dnaIReUSOM+tJc8r
	Z+6/rj/oXh5WiR1PRChg0MV0uj+VEPx7pW2vOACBne5Z6FgJdDXec6UZ3F6zrj3jAw3A=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml: GC parameter tuning
Message-Id: <E1oq93s-0006Zl-Nl@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:25:24 +0000

commit 276908c6c1bcf5ecc5c5bf0d4640c68b12bd3c35
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 4a8bacff20b857ca0d628ef5525877ade11f2a42)
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 96c125a969..1a5d2f34a6 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -26,6 +26,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 369b5036f4..0b6343dfc7 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -229,6 +230,67 @@ let to_file store cons file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -238,6 +300,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:25:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:25:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435596.689135 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq944-0007nO-3B; Wed, 02 Nov 2022 08:25:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435596.689135; Wed, 02 Nov 2022 08:25:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq944-0007nG-0U; Wed, 02 Nov 2022 08:25:36 +0000
Received: by outflank-mailman (input) for mailman id 435596;
 Wed, 02 Nov 2022 08:25:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq942-0007n8-Rm
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq942-0005D0-R9
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq942-0006aF-Qa
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=wm3690mYEQkoRs95o+pW5yLHWjfhCstd8eCbocE1fvU=; b=cLVhtRVS2IfYS0FC5g/5RPDZ/e
	7R90harna8i0DfL5vuGBJ7nCfN0yDhHDBF47zvHbYSpZceA+Vm/VkJnOMTPuYUyGyHfw5fiKSmtrJ
	m/fexpt5pK8JjXfT/70hEv6eFfQ7/38sL1mAaaH2bt7x9pyCc6YgloSWuzETHpAcazaI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml/libs/xb: hide type of Xb.t
Message-Id: <E1oq942-0006aF-Qa@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:25:34 +0000

commit 3a67865614eff0988332ed68876e7b9512a5453e
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Fri Jul 29 18:53:29 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml/libs/xb: hide type of Xb.t
    
    Hiding the type will make it easier to change the implementation
    in the future without breaking code that relies on it.
    
    No functional change.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba)
---
 tools/ocaml/libs/xb/xb.ml           | 3 +++
 tools/ocaml/libs/xb/xb.mli          | 9 ++-------
 tools/ocaml/xenstored/connection.ml | 4 +---
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 104d319d77..8404ddd8a6 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out
 let input_len con = Queue.length con.pkt_in
 let has_in_packet con = Queue.length con.pkt_in > 0
 let get_in_packet con = Queue.pop con.pkt_in
+let has_partial_input con = match con.partial_in with
+	| HaveHdr _ -> true
+	| NoHdr (n, _) -> n < Partial.header_size ()
 let has_more_input con =
 	match con.backend with
 	| Fd _         -> false
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 3a00da6cdd..794e35bb34 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,13 +66,7 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
-type t = {
-  backend : backend;
-  pkt_in : Packet.t Queue.t;
-  pkt_out : Packet.t Queue.t;
-  mutable partial_in : partial_buf;
-  mutable partial_out : string;
-}
+type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
 val queue : t -> Packet.t -> unit
@@ -97,6 +91,7 @@ val has_output : t -> bool
 val peek_output : t -> Packet.t
 val input_len : t -> int
 val has_in_packet : t -> bool
+val has_partial_input : t -> bool
 val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index daf8d804f7..70c4348552 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -125,9 +125,7 @@ let get_perm con =
 let set_target con target_domid =
 	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
 
-let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with
-	| Xenbus.Xb.Xenmmap _ -> true
-	| _ -> false
+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
 let send_reply con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:25:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:25:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435597.689139 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94E-0007q7-4l; Wed, 02 Nov 2022 08:25:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435597.689139; Wed, 02 Nov 2022 08:25:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94E-0007pz-20; Wed, 02 Nov 2022 08:25:46 +0000
Received: by outflank-mailman (input) for mailman id 435597;
 Wed, 02 Nov 2022 08:25:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94C-0007pm-V3
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94C-0005DC-UG
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94C-0006ae-TU
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=l6gYc6H9FDbKZhfSx9gcQQMI7xSKJrLdvps4Y1oMplE=; b=xsuhrKUMsdMNXQQlYxrBsGAlWM
	DW9gMtW2JC49ZLj3StRkhkuf6KoiQLReMBEuYb3AeHRLB6jI2cZvXN+gPcwnaYR9z+Wu7eS5faIFj
	5+OvkMcyTxKBJcdDTshstBnDmHxXgn53y96+wLAMLE2WNOQnd/FX4tPULzjWrlQ4qCcY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1oq94C-0006ae-TU@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:25:44 +0000

commit 7f5d36df7c72f5f83a0027de45cb314c63f07f8f
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c0a86a462721008eca5ff733660de094d3c34bc7)
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  2 --
 tools/ocaml/xenstored/process.ml    | 12 ++++++------
 5 files changed, 18 insertions(+), 39 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 70c4348552..ace2aa5b4f 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,8 +277,6 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 3279b19b1b..72629ee38b 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -570,16 +570,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -589,8 +590,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:25:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:25:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435598.689142 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94O-0007se-5u; Wed, 02 Nov 2022 08:25:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435598.689142; Wed, 02 Nov 2022 08:25:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94O-0007sX-3R; Wed, 02 Nov 2022 08:25:56 +0000
Received: by outflank-mailman (input) for mailman id 435598;
 Wed, 02 Nov 2022 08:25:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94N-0007sJ-1g
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94N-0005Df-0y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94N-0006bK-0E
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:25:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NVXcK+93jv4BgctoipxlpzwpJJntWkSlaKk/tkvsEvg=; b=OADvETajvhLe1K1p2O/Z1SGkhF
	hZFIXl8MXTEOzoJEf29XwyF4ix/Budu+FaILb1nDAYSyD/iqw+5ZxK3wYFVO5p52jhfxJwFfu+oR3
	uvDWqlvtbbtptzL6llwz+0/5w8kaWjulWf57734APrONQhwiR4AB05bNe9UFbgOKd+Jg=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1oq94N-0006bK-0E@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:25:55 +0000

commit b8b3734996f7ce0bfe2e28abed0eeab22d492a19
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 19171fb5d888b4467a7073e8febc5e05540956e9)
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:26:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:26:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435599.689147 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94Y-0007vF-7l; Wed, 02 Nov 2022 08:26:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435599.689147; Wed, 02 Nov 2022 08:26:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94Y-0007v8-59; Wed, 02 Nov 2022 08:26:06 +0000
Received: by outflank-mailman (input) for mailman id 435599;
 Wed, 02 Nov 2022 08:26:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94X-0007ux-4x
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94X-0005Dw-4E
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94X-0006c8-3U
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=WJM5W5lbZmQcw+GN4s1ceqTmhdj2y4OLioru8JNnLoI=; b=gjZE8ZFfmUXb2AClam9WSWvQa4
	ioBsYTdclNXWAeuNI3C8C5O+3PB9Jon35snCDbTx/YZZJlX6eFJHMtsnLmxcdR23+ZOWMMwMnnTGM
	GSRkoPePoy+ey0cnuqOBmqR5HTvzBefM4U5FWDiC5SQ8j/Thc5uDjB/s+TYXTSemqelc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1oq94X-0006c8-3U@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:26:05 +0000

commit 8db5e6f48e0794b16d0cec8ca79f3ba250835055
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96)
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index ace2aa5b4f..9aad451a2d 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -279,6 +407,7 @@ let get_transaction con tid =
 let do_input con = Xenbus.Xb.input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -286,7 +415,7 @@ let peek_output con = Xenbus.Xb.peek_output con.xb
 let do_output con = Xenbus.Xb.output con.xb
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 7efdf3e5e0..39190c19ec 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: (string, Connection.watch list) Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd _can_write =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -196,3 +215,13 @@ let debug cons =
 	let anonymous = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.anonymous [] in
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
+
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 1a5d2f34a6..9e52367094 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 72629ee38b..d2a3ba064e 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -56,7 +56,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -66,8 +66,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -99,6 +100,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -207,7 +222,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -366,7 +381,7 @@ let do_watch con t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -397,7 +412,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -565,7 +580,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -593,6 +609,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 0b6343dfc7..4f8fab2dd1 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -102,6 +102,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:26:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:26:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435600.689150 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94i-0007yk-As; Wed, 02 Nov 2022 08:26:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435600.689150; Wed, 02 Nov 2022 08:26:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94i-0007yd-8Q; Wed, 02 Nov 2022 08:26:16 +0000
Received: by outflank-mailman (input) for mailman id 435600;
 Wed, 02 Nov 2022 08:26:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94h-0007yT-7i
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94h-0005EC-75
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94h-0006cd-6T
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=/eg9X8Wt4S8ddYNCscbb8frEysp07tgGL0Z14ODlnxc=; b=I2l/0r8P696W+fsfyd0f20eQOX
	lQ5qO82SZcVYNzffxYrwG/NopcLXrbd/weMYqJsCs6crntBopeUWLw1+Sg5b37JV6wrbdPXhELFS9
	hHyEBePAYkdVS1DZbfdike/hgOidM/EQcgz9UsNVcWvHSzOkKvsLHU2HwWUS7x2ydBFA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1oq94h-0006cd-6T@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:26:15 +0000

commit 2cf13721414dc5b380dc3c60e0f20c9cb416dbb3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit c7bc20d8d123851a468402bbfc9e3330efff21ec)
---
 SUPPORT.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/SUPPORT.md b/SUPPORT.md
index c45390a245..dd9702bfe4 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -175,6 +175,17 @@ Support for running qemu-xen device model in a linux stubdomain.
 
     Status: Tech Preview
 
+## Xenstore
+
+### C xenstored daemon
+
+    Status: Supported
+
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+
 ## Toolstack/3rd party
 
 ### libvirt driver for xl
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:26:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:26:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435601.689154 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94s-00081q-Cf; Wed, 02 Nov 2022 08:26:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435601.689154; Wed, 02 Nov 2022 08:26:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq94s-00081i-9v; Wed, 02 Nov 2022 08:26:26 +0000
Received: by outflank-mailman (input) for mailman id 435601;
 Wed, 02 Nov 2022 08:26:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94r-00081R-B0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94r-0005EG-AI
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq94r-0006d6-9i
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=++wgwzVZmrONkeP0nUnyDOduxC3rg2hlkhEKGnv9Ac0=; b=7CDy64hNX40RWJHWUVO2GbJ5Bl
	t+2ENdCDHiR3d5cLiPcIipLkqmWahVNZf3X6crsIY80MBllDRC3BsKZ1X4dn1x1tXPGhJTii4lHdN
	/MrW6Wqcz/EDmRNYpl3wdQxKBbILSiC5dPISlamjlz9HR23y1JWfgLQmLf3oErgRR/nw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1oq94r-0006d6-9i@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:26:25 +0000

commit 55e23bf410bf20d27ef5555a73eab2a8a2602b39
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2a587de219cc0765330fbf9fac6827bfaf29e29b)
---
 tools/xenstore/xenstored_control.c     | 29 ++++++-------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 27 +++++++-----
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 116 insertions(+), 75 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 0227a55656..05e38e576a 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -30,11 +30,11 @@
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -46,7 +46,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -147,7 +147,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -159,7 +159,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -172,7 +172,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 }
 
 #ifdef __MINIOS__
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	if (num)
@@ -184,7 +184,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 #else
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -199,7 +199,7 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -239,7 +239,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -251,7 +251,7 @@ static int do_control_print(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -268,7 +268,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd, len = 0;
@@ -304,7 +304,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	int num;
 	int cmd;
@@ -316,7 +317,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (num < 1)
 		return EINVAL;
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) != num)
@@ -324,7 +325,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 
 	for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++)
 		if (streq(vec[0], cmds[cmd].cmd))
-			return cmds[cmd].func(in, conn, vec + 1, num - 1);
+			return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 
 	return EINVAL;
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index 207e0a6fa3..faa955968d 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,4 +16,5 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 6ed1ae2614..28724ef10a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1147,11 +1147,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1160,7 +1162,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1172,7 +1174,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1199,7 +1202,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1215,11 +1218,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1399,7 +1404,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1413,12 +1419,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1429,18 +1435,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1448,10 +1455,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 		/* No permissions? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1549,22 +1556,23 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1579,7 +1587,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1589,13 +1597,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1608,7 +1618,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1625,7 +1636,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1640,7 +1651,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1675,7 +1686,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1683,7 +1694,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1756,6 +1768,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	if ((unsigned int)type >= XS_TYPE_COUNT || !wire_funcs[type].func) {
 		eprintf("Client unknown operation %i", type);
@@ -1776,10 +1789,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 47e8010b34..417ff81181 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -333,7 +333,7 @@ bool domain_can_write(struct connection *conn)
 	return ((intf->rsp_prod - intf->rsp_cons) != XENSTORE_RING_SIZE);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -475,7 +475,8 @@ static void domain_conn_reset(struct domain *domain)
 }
 
 /* domid, gfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -551,7 +552,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -598,7 +600,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -613,7 +616,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -628,7 +632,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -636,18 +641,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -668,7 +672,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index e013a9991c..732eb8fa75 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -22,25 +22,32 @@
 void handle_event(void);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(void);
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6e29118c80..cd592845e7 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -487,7 +487,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -500,8 +501,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -548,7 +549,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -564,8 +566,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	list_del(&trans->list);
 	conn->transaction_started--;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 19d0fb01b1..13627ce972 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -184,7 +184,7 @@ static int destroy_watch(void *_watch)
 	return 0;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -200,7 +200,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 		/* check if valid event */
 	} else {
 		relative = !strstarts(vec[0], "/");
-		vec[0] = canonicalize(conn, in, vec[0]);
+		vec[0] = canonicalize(conn, ctx, vec[0]);
 		if (!vec[0])
 			return ENOMEM;
 		if (!is_valid_nodename(vec[0]))
@@ -250,7 +250,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -258,7 +259,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 03094374f3..40455dff5d 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:26:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:26:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435602.689158 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq952-00084g-Ef; Wed, 02 Nov 2022 08:26:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435602.689158; Wed, 02 Nov 2022 08:26:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq952-00084Y-BY; Wed, 02 Nov 2022 08:26:36 +0000
Received: by outflank-mailman (input) for mailman id 435602;
 Wed, 02 Nov 2022 08:26:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq951-00084M-EM
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq951-0005EO-DI
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq951-0006dV-Cg
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=3qWUZNLfrx7orJBnz6BedXynJAjCiSwv7MLJa/1gYT0=; b=mCNG+7EKQhiIARe5A5dTv3FtME
	ScnxhG6PgBQVJ/XA3YydxJBSRwMR4P1iBO/QzSDZcBU4yKRSWV4h6Zwz1cHhFjo7FEr3Q3s6CsLRC
	6beDBkvBnpChbq20Zzh8KSf+ElmuCXg9Hwgao8chLbSx9WUf/yjwN4O0xnVJLd/zgdDk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: fix checking node permissions
Message-Id: <E1oq951-0006dV-Cg@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:26:35 +0000

commit 2761f00a40665e97e1851880089fc888b378efc7
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ab128218225d3542596ca3a02aee80d55494bef8)
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 28724ef10a..34a8469dd6 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1642,6 +1642,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 417ff81181..8dcc1c20ab 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -859,7 +859,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -867,20 +866,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -893,8 +910,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -911,8 +926,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 732eb8fa75..bab405209e 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,6 +65,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:26:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:26:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435603.689163 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95C-00087s-Hz; Wed, 02 Nov 2022 08:26:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435603.689163; Wed, 02 Nov 2022 08:26:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95C-00087l-FF; Wed, 02 Nov 2022 08:26:46 +0000
Received: by outflank-mailman (input) for mailman id 435603;
 Wed, 02 Nov 2022 08:26:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95B-00087b-Gv
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95B-0005Fz-GE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95B-0006dy-Ff
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=HmeHV+Es+TeOY42G23BEcMYbPYC8iFIoqokZjtyYCj8=; b=Kubvt9PPkqDefBjYn3lEkMw3Xa
	A6sJQ2wCL7IHPCgqS/N4lCWwHO31ViGwq9zcKQCgsDP44QW2m0C+fUSsITrlxO/Nn1s63gg3ocSVx
	UG/UrNqqtIkrtRHmWChc53eaPzK5g3IjXB69AQz+VSoH0p1W+mtFEO9YQQoecwSTrwwY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1oq95B-0006dy-Ff@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:26:45 +0000

commit 4d2fe1d32c3bb6e966522840e2080377db9e9f65
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit da8ee25d02a5447ba39a9800ee2a710ae1f54222)
---
 tools/xenstore/xenstored_core.c | 110 ++++++++++++++++++++++++++--------------
 1 file changed, 72 insertions(+), 38 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 34a8469dd6..e7971c828e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1254,57 +1254,91 @@ static char *basename(const char *name)
 	return strrchr(name, '/') + 1;
 }
 
-static struct node *construct_node(struct connection *conn, const void *ctx,
-				   const char *name)
+static int add_child(const void *ctx, struct node *parent, const char *name)
 {
 	const char *base;
 	unsigned int baselen;
-	struct node *parent, *node;
-	char *children, *parentname = get_parent(ctx, name);
-
-	if (!parentname)
-		return NULL;
+	char *children;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
-
-	/* Add child to parent. */
 	base = basename(name);
 	baselen = strlen(base) + 1;
 	children = talloc_array(ctx, char, parent->childlen + baselen);
 	if (!children)
-		goto nomem;
+		return ENOMEM;
 	memcpy(children, parent->children, parent->childlen);
 	memcpy(children + parent->childlen, base, baselen);
 	parent->children = children;
 	parent->childlen += baselen;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
-
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
-
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
+	return 0;
+}
+
+static struct node *construct_node(struct connection *conn, const void *ctx,
+				   const char *name)
+{
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
+
+	if (!parentname)
+		return NULL;
+
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
+
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
+
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
+
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
+
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:26:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:26:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435604.689167 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95M-0008AU-Jr; Wed, 02 Nov 2022 08:26:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435604.689167; Wed, 02 Nov 2022 08:26:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95M-0008AM-H8; Wed, 02 Nov 2022 08:26:56 +0000
Received: by outflank-mailman (input) for mailman id 435604;
 Wed, 02 Nov 2022 08:26:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95L-0008A7-Jw
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95L-0005GJ-JE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95L-0006eN-Id
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:26:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NT+wzVOXrHl7EVbZZ+UkhnUGSSQbBQvzD+oljxm/Fvw=; b=c0AF7fqhoTU5O0EIQlGsdZ3LaS
	MVa0s95U5GJnIJYSxnNIwcCzjFnCSu4Kv793hJMX+DibUqlVMYsrNpbtY2yk/yAisxMOTVwgCU1nr
	tvPaX/lrZUtbqEk+bvnjZmph/202YDHSOKDkW5epafo5HHETmwNEkNa6gsrK18xtHzZM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1oq95L-0006eN-Id@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:26:55 +0000

commit 7d4c2dea43b07249bfb6392e442afef4189b12a8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4)
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index e7971c828e..cef9fc1c1e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1505,15 +1505,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1523,7 +1523,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2125,6 +2127,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2173,12 +2186,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2195,11 +2203,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:27:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:27:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435605.689172 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95W-0008FA-N0; Wed, 02 Nov 2022 08:27:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435605.689172; Wed, 02 Nov 2022 08:27:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95W-0008F2-Ie; Wed, 02 Nov 2022 08:27:06 +0000
Received: by outflank-mailman (input) for mailman id 435605;
 Wed, 02 Nov 2022 08:27:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95V-0008Ev-N0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95V-0005Ga-MG
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95V-0006ex-LZ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=D5WE6NFQdgGnqF8RUcQ643h+EZFGnwNHvZQ97iCH/Zg=; b=rMwxqduWusXPXa/sP+N/hGZvc2
	FZSh9PLCYeSEk+PY0TtaN3j/dhJ1Vzq1L3+b2T58W85eCT86yx7r369TIycPouNv4F5hu7GR7L5ph
	HuBaE1rK2cOR5vQUlGBqCfBCzLgnm1Uyp+vGMUi8aDTtNYIMQ/TWyM/KJOSy2rKzg2ew=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: add generic treewalk function
Message-Id: <E1oq95V-0006ex-LZ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:27:05 +0000

commit 4e1974248e895158e546e2294e87a0905217ce19
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 0d7c5d19bc27492360196e7dad2b227908564fff)
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index cef9fc1c1e..47559a85d4 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1733,6 +1733,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2105,18 +2234,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2172,7 +2289,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 5abf06c21c..fc9882ac37 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -167,6 +167,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -278,6 +279,45 @@ int do_tdb_delete(struct connection *conn, TDB_DATA *key,
 
 void conn_free_buffered_data(struct connection *conn);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:27:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:27:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435606.689175 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95g-0008I0-Mq; Wed, 02 Nov 2022 08:27:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435606.689175; Wed, 02 Nov 2022 08:27:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95g-0008Hs-KC; Wed, 02 Nov 2022 08:27:16 +0000
Received: by outflank-mailman (input) for mailman id 435606;
 Wed, 02 Nov 2022 08:27:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95f-0008Hi-Q3
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95f-0005Ge-PK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95f-0006fU-Oe
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Ty5KyUpsdf8jau8y4gVGXQUZ8Dbcc80BoBzx5u3+imU=; b=xPlfcpTVCf1cFh2DIkx3XgjaKo
	uL64NggwE6sVnTqjpeZNVgFd5bDqQds3jalh+ZC0LmPwfhHZSlzJ8kPN0m5/n5IFmKAMp3CJd+PA7
	iBY8UyKzJ4OgOPhVwUlbs9fDYDV6cWFmP3g9umtUKF25su7JanZ1WjUbv58A0uwH+DIk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: simplify check_store()
Message-Id: <E1oq95f-0006fU-Oe@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:27:15 +0000

commit 1de79dcf1bf08dd71ebfa083ff2365f06f69cd6e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 70f719f52a220bc5bc987e4dd28e14a7039a176b)
---
 tools/xenstore/xenstored_core.c | 43 ++++++++++++++---------------------------
 1 file changed, 15 insertions(+), 28 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 47559a85d4..302fb5b93c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2277,46 +2277,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2326,19 +2314,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:27:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:27:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435607.689179 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95q-0008Kl-Oy; Wed, 02 Nov 2022 08:27:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435607.689179; Wed, 02 Nov 2022 08:27:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq95q-0008Kd-Lm; Wed, 02 Nov 2022 08:27:26 +0000
Received: by outflank-mailman (input) for mailman id 435607;
 Wed, 02 Nov 2022 08:27:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95p-0008KX-Sw
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95p-0005Gs-SJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95p-0006fv-Rh
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=j74YO8B9Hiv63WYYSxMVG0dOHiW91zgC1+rM1AiUdlo=; b=RaNQntSrXaJuLxJKjLxvbbAu32
	4TUewoYIO33JWZepVRXMs19FNs1mAQbkWuRDsYIY1YL5NjvZAjn4BTbphJ05SrZSoPnYreH5UGBKf
	1rDpY4bdWMtBCI0oFlyAlmHBdzdPHMzj8nG8FFjVcr/F9lQqvUIcUsUezRCDIi2MYxC8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: use treewalk for check_store()
Message-Id: <E1oq95p-0006fv-Rh@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:27:25 +0000

commit 7f969f391e7714c20a50f1bee108e04c07f971f1
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit a07cc0ec60612f414bedf2bafb26ec38d2602e95)
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++-----------------------------
 1 file changed, 28 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 302fb5b93c..1cc11d0b1c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2244,18 +2244,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2269,70 +2257,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
-
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
+	struct hashtable *reachable = arg;
 
-			childnode = read_node(NULL, childname, childname);
-
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2381,24 +2328,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char * root = talloc_strdup(NULL, "/");
-	struct hashtable * reachable =
-		create_hashtable(16, hash_from_key_fn, keys_equal_fn);
- 
+	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
+
+	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
 		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:27:37 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:27:37 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435608.689183 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq961-0008O4-SC; Wed, 02 Nov 2022 08:27:37 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435608.689183; Wed, 02 Nov 2022 08:27:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq961-0008Nv-PW; Wed, 02 Nov 2022 08:27:37 +0000
Received: by outflank-mailman (input) for mailman id 435608;
 Wed, 02 Nov 2022 08:27:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq960-0008Nl-1p
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95z-0005H1-WF
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq95z-0006gP-Ue
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Nf66w1TZ8dGGUu6JZxaK8cC30yR5nEhy2rbqJw+H/Is=; b=J5/4wm09xE4JRL7Zb63pUiLbYe
	zKDKloMNTgEh/ofHUt2zX4lpgC/Eaj/UkTHJgDhySB3RGc27Oox1jzpjv5zqI4vak5sqDhXtw4bLm
	f92QW8HKWzhATGlrxeFtKO4iOq3V2vGQj2kyQEUOgGGKoihLm9uLJrAXLQx9TtRmsPzA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1oq95z-0006gP-Ue@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:27:35 +0000

commit baa5f58a69b32691bf0f1e98555ebe0bfd9e6314
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit ea16962053a6849a6e7cada549ba7f8c586d85c6)
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 1cc11d0b1c..5bb7b85213 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1233,21 +1233,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1516,69 +1501,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1586,9 +1561,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1623,7 +1610,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:27:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:27:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435609.689188 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96B-0008R0-UO; Wed, 02 Nov 2022 08:27:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435609.689188; Wed, 02 Nov 2022 08:27:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96B-0008Qq-R1; Wed, 02 Nov 2022 08:27:47 +0000
Received: by outflank-mailman (input) for mailman id 435609;
 Wed, 02 Nov 2022 08:27:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96A-0008Qc-45
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96A-0005HO-3N
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96A-0006gy-2j
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=AO16d1WpJAZtqrvzoWwm2+ET97TqJuIrnOMCm8Ao/RE=; b=G45iBJEdoVSvG7n8dMeVRysA+A
	hRhh2D96Ev6/qxNcBsdIYp8L8fAAKAPP3vaSpFq6qG1lT64m4gHX1n8+GP6NZCD1fDpJTscMb9h1f
	1FuzuVdQA0Y5/yp5oQ4Zif1Q3fP/phKM2/cqJGpdFNtdViEOjWVFcK9LDxwMdtr01MwU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1oq96A-0006gy-2j@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:27:46 +0000

commit e5bdcec53ad9c247d90d22cca6fb0b66e35cb81c
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 755d3f9debf8879448211fffb018f556136f6a79)
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 85 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 81 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5bb7b85213..eb1d7c2b3b 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -79,6 +79,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -664,7 +665,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -707,7 +708,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1548,7 +1549,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1610,7 +1611,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2446,6 +2447,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2469,6 +2472,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 	{ NULL, 0, NULL, 0 } };
@@ -2543,7 +2547,7 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:Q:q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2579,6 +2583,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index fc9882ac37..ec24c27ac2 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -204,6 +204,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(void);
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
 void check_store(void);
@@ -242,6 +245,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8dcc1c20ab..e798cd7475 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -200,10 +200,65 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		key.dptr = (char *)node->name;
+		key.dsize = strlen(node->name);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -835,15 +890,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -904,23 +959,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -938,15 +981,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1065,7 +1108,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index bab405209e..5bd253395d 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -64,7 +64,7 @@ bool domain_can_write(struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:27:57 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:27:57 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435610.689190 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96L-0008Tc-VA; Wed, 02 Nov 2022 08:27:57 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435610.689190; Wed, 02 Nov 2022 08:27:57 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96L-0008TU-Sa; Wed, 02 Nov 2022 08:27:57 +0000
Received: by outflank-mailman (input) for mailman id 435610;
 Wed, 02 Nov 2022 08:27:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96K-0008TJ-7D
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96K-0005HZ-6X
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96K-0006hV-5m
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:27:56 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=tDkvw5NG02uQAIw+YfZCgkK5Wv6vIRfSJ/DOqp3FzIk=; b=ExlAdRVXA/REr6rdjeGTuKRagx
	LpxM1uaqEcEw00f23f9e37ItMaVEagQQp7jKGQAizA5jLGwJ2nZ07qelA/4/RG7UJ7wTzxt/O8rU+
	4UJG1Z6OJgbghHWeYqQ31OdD3WXvGIBdvLHluzprycN++nzbqv3CW2fIoEpqhqnUKs8E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: make the internal memory data base the default
Message-Id: <E1oq96K-0006hV-5m@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:27:56 +0000

commit 39254879e3ec7e765097eb9f27b2773309735cab
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d174fefa90487ddd25ebc618028f67b2e8a1f795)
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 4ce8299c3c..2dfc78d4de 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -137,9 +137,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom = xc_dom_allocate(xch, cmdline, NULL);
     if ( !dom )
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index eb1d7c2b3b..7ed852fd79 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2134,7 +2134,7 @@ static void accept_connection(int sock, bool canwrite)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2446,7 +2446,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2471,7 +2472,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2547,7 +2548,8 @@ int main(int argc, char *argv[])
 	int timeout;
 
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:Q:q:T:RVW:w:", options,
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:Q:q:T:RVW:w:", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2581,7 +2583,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:28:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:28:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435611.689195 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96W-000058-0h; Wed, 02 Nov 2022 08:28:08 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435611.689195; Wed, 02 Nov 2022 08:28:07 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96V-00004z-U7; Wed, 02 Nov 2022 08:28:07 +0000
Received: by outflank-mailman (input) for mailman id 435611;
 Wed, 02 Nov 2022 08:28:06 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96U-0008WN-AD
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:06 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96U-0005Hw-9S
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:06 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96U-0006iK-8h
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:06 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=nBCbHUEPcO/2tovU6ofi0pTWcJGkLj8f8V08x2rNIiQ=; b=VUu5eLDweVEfSOjTeHvuftEbY9
	UFRGwYBYeLpc4idYSDuaWjAPbBcyW3cfSe1lyzq3fvRH5c7W4kJsFIwdV/YjN2AV8bCfeRB3VZUWQ
	zlsWctlseNnlO6U5oTwZTmYhPdcOTNNV24nnpHN+9eLHdq2c4OBhDBlWyxw4Z7Twegl0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] docs: enhance xenstore.txt with permissions description
Message-Id: <E1oq96U-0006iK-8h@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:28:06 +0000

commit 7036cb93e334e006fe3b9685256fd75e4967e3fc
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit d084d2c6dff7044956ebdf83a259ad6081a1d921)
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 1f42a377c1..6aa07c5ed8 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:28:18 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:28:18 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435612.689200 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96g-00008Z-4Q; Wed, 02 Nov 2022 08:28:18 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435612.689200; Wed, 02 Nov 2022 08:28:18 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96g-00008R-1A; Wed, 02 Nov 2022 08:28:18 +0000
Received: by outflank-mailman (input) for mailman id 435612;
 Wed, 02 Nov 2022 08:28:16 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96e-00008J-DY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:16 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96e-0005I6-CL
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:16 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96e-0006j7-Bi
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:16 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=+R7iagAvufqzOc7PEOrgTbWBzGts4F3AhE7R38pAgTk=; b=bB+/IMU3b1YjPabQvmdPXBSLf8
	a+8itdYv0zV+Xw1h4A/H1Jg9ozF/C7OvEpvFxFKOVq6BIW1sIFq06yuF9tV+yxM57H3vqZmMnzSci
	eUf12XBFCHSEPDKZwFSEgNu5E0bT1NB77u0BqOA/zbvVUY8JorVCAF7e6//IKtzZPcA8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1oq96e-0006j7-Bi@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:28:16 +0000

commit 0cd209a7e302f0754b19d38143932c3c10d4d7cc
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit db471408edd46af403b8bd44d180a928ad7fbb80)
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 328d3a5198..d82764f60f 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -89,10 +89,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; List.iter (recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = List.rev_map walk node.children |> List.rev }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			List.rev_map walk node.children |> List.filter is_valid |> List.rev } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -446,11 +457,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:28:28 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:28:28 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435613.689202 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96q-0000Bd-5J; Wed, 02 Nov 2022 08:28:28 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435613.689202; Wed, 02 Nov 2022 08:28:28 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq96q-0000BW-2m; Wed, 02 Nov 2022 08:28:28 +0000
Received: by outflank-mailman (input) for mailman id 435613;
 Wed, 02 Nov 2022 08:28:26 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96o-0000BO-G1
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:26 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96o-0005IJ-FP
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:26 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96o-0006jk-Eg
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:26 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=uPkObWbROktmp+YGyHDjeNCr4L92pF6zixkSoZ5mWy4=; b=fNcyS+Bbwz71RMeJEgEJSu+Yub
	Ie0sjcmYSt1MWLDVYSfdpfeddSab370+EqPR/ONCj1ZZJxKm2lKVCisF1CAKwP0Ll17Xxe6mPszPY
	+LfEN44L2WnjUtGg7N2R/TZ27SoF/3TJqqEfvct6XwmEwPkKCABd5QuZX6P15r0KFAaI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1oq96o-0006jk-Eg@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:28:26 +0000

commit ecbfb3bd49526adf48f739445502aaff8e69e442
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    (cherry picked from commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3)
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index d2a3ba064e..027252ece8 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -587,7 +587,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:28:38 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:28:38 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435614.689207 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq970-0000EM-6w; Wed, 02 Nov 2022 08:28:38 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435614.689207; Wed, 02 Nov 2022 08:28:38 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq970-0000EE-4I; Wed, 02 Nov 2022 08:28:38 +0000
Received: by outflank-mailman (input) for mailman id 435614;
 Wed, 02 Nov 2022 08:28:36 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96y-0000Dw-Iz
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:36 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96y-0005IZ-IE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:36 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq96y-0006kV-Ha
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:36 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=1PfT7/eaLS8dukMszoojXmg9w1ottqgGT/tMKUI+Thg=; b=Ny4N5oyL0EJ8OD4D78In2ZVztU
	BFMw6OLfcyOTXmOr4Jz03w/2DRDKMQXHn40ewUfjDIqHRaHNjTtUz5QuZJmIQQpAPUqkCt/rsnSwB
	kvo6aE8VH3L4g7rL+zO/K0S2f37r4VMifWlsBdFO1i53pIOpPkbkbIVvBzxJgBnWl2RM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: fix deleting node in transaction
Message-Id: <E1oq96y-0006kV-Ha@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:28:36 +0000

commit fd44be9ccb0b8704497498e45e020738a11d27e3
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187)
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd592845e7..6297149986 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -424,7 +424,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 08:28:48 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 08:28:48 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435615.689211 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq97A-0000HJ-8l; Wed, 02 Nov 2022 08:28:48 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435615.689211; Wed, 02 Nov 2022 08:28:48 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oq97A-0000HB-5k; Wed, 02 Nov 2022 08:28:48 +0000
Received: by outflank-mailman (input) for mailman id 435615;
 Wed, 02 Nov 2022 08:28:46 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq978-0000Gv-MA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:46 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq978-0005J5-LK
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:46 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oq978-0006l2-KV
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 08:28:46 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=eKQg5qQJHJLG8IHPuMcIv5rjIJhegFYigsbEA+vX3Xc=; b=vip+FmiaK1Ec1u7BHC38GDpdsQ
	n0fIh9Zy1HH6gHL967ozmw1stDc41npIIM0vMqD1mVlB/vmQOhye0XetN0RiZJxhGN0m+s0Wn8fbE
	LvrN20rpBG9dUInvxHMrXa1jsNtYBKcjvSjjbonzXokI82qpdK8OwcXtTHvX/3+z+Ono=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1oq978-0006l2-KV@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 08:28:46 +0000

commit 1c354767d58cd80224f0dfb107584bc8bd629b00
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 15:20:41 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    (cherry picked from commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff)
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 7ed852fd79..64ff80f5c5 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -634,8 +634,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -748,10 +747,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 enum xs_perm_type perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 6297149986..5e4780e874 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -205,25 +206,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -246,7 +242,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -265,10 +260,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -279,9 +270,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -308,7 +300,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -327,7 +319,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -339,7 +331,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -377,100 +368,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -560,6 +541,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -581,13 +563,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -661,7 +647,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -673,11 +659,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 11:11:11 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 11:11:11 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435799.689578 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBeE-00083U-Eh; Wed, 02 Nov 2022 11:11:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435799.689578; Wed, 02 Nov 2022 11:11:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBeE-00083N-BP; Wed, 02 Nov 2022 11:11:06 +0000
Received: by outflank-mailman (input) for mailman id 435799;
 Wed, 02 Nov 2022 11:11:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeD-00083H-6V
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeC-0008D0-VF
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeC-0006Go-Sc
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=nXAfZF86UNO7/W2Tkm6sCQJVfmxpC6fAQUhfM/FvvB0=; b=OBdmvCFRBahtzHjJAhBpk5He6x
	L5t6K/rsPhsw6Z+olwpMBOAKWgAKQ1TdTsM8yCDhbWSwaKInWR2Sy5mL9xPbYpiMhxvDZzw8Jo+kh
	IXD8f39j+whD8KL2uCBe7+s8/PxAISp8zO1boBg8XBmkeJ9lDc0Df1Jls2CDkASziLgw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] hvm/msr: load VIRT_SPEC_CTRL
Message-Id: <E1oqBeC-0006Go-Sc@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 11:11:04 +0000

commit 0d251a1dd15f9c406de2d7d7fe018c4e6e454215
Author:     Roger Pau Monné <roger.pau@citrix.com>
AuthorDate: Wed Nov 2 12:06:37 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:06:37 2022 +0100

    hvm/msr: load VIRT_SPEC_CTRL
    
    Add MSR_VIRT_SPEC_CTRL to the list of MSRs handled by
    hvm_load_cpu_msrs(), or else it would be lost.
    
    Fixes: 8ffd5496f4 ('amd/msr: implement VIRT_SPEC_CTRL for HVM guests on top of SPEC_CTRL')
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/arch/x86/hvm/hvm.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 44b432ec5a..15a9b34c59 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -1498,6 +1498,7 @@ static int cf_check hvm_load_cpu_msrs(struct domain *d, hvm_domain_context_t *h)
         case MSR_INTEL_MISC_FEATURES_ENABLES:
         case MSR_IA32_BNDCFGS:
         case MSR_IA32_XSS:
+        case MSR_VIRT_SPEC_CTRL:
         case MSR_AMD64_DR0_ADDRESS_MASK:
         case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
             rc = guest_wrmsr(v, ctxt->msr[i].index, ctxt->msr[i].val);
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 11:11:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 11:11:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435800.689582 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBeO-00085y-HB; Wed, 02 Nov 2022 11:11:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435800.689582; Wed, 02 Nov 2022 11:11:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBeO-00085q-EY; Wed, 02 Nov 2022 11:11:16 +0000
Received: by outflank-mailman (input) for mailman id 435800;
 Wed, 02 Nov 2022 11:11:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeN-00085b-5F
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeN-0008D4-35
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeN-0006HF-2A
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=HaYxWvzMXrzQ8s1ifwzIwIMrbamHcezYGrOoDL1xKes=; b=jQHRfc1MuXbp1QiUJpXkRqvX5l
	vfS9JACNn9EUPxQTr5w05uMDaYJk3plGlhPdPCOwVCLmFgWmzFgYj+EWZ8KdPEjGfeh9hcbb+5gbC
	ZbYYNq3EZAMnRRAgX9tgYsMTQk9HATzCvW8LPq476ugjUT56cTtWAa9627E6i9cVNbH0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: remove XEN_LIB_STORED and XENSTORED_ROOTDIR
Message-Id: <E1oqBeN-0006HF-2A@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 11:11:15 +0000

commit 1283af6465cd14934e89a088f8abef577d013761
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 2 12:07:57 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:07:57 2022 +0100

    tools/xenstore: remove XEN_LIB_STORED and XENSTORED_ROOTDIR
    
    XEN_LIB_STORED is serving no real purpose, as it is a mount point for
    a tmpfs, so it can be replaced easily by XEN_RUN_STORED.
    
    XENSTORED_ROOTDIR is basically unused already, there is just a single
    reference in xs_daemon_rootdir() with a fallback to XEN_LIB_STORED,
    and a .gdbinit file setting it.
    
    Remove the .gdbinit file, as it is not known having been used since
    ages, and make xs_daemon_rootdir() an alias of xs_daemon_rundir().
    
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 config/Paths.mk.in                                     |  1 -
 configure                                              |  4 ----
 docs/configure                                         |  4 ----
 m4/paths.m4                                            |  3 ---
 tools/configure                                        |  7 +------
 tools/configure.ac                                     |  1 -
 tools/hotplug/FreeBSD/rc.d/xencommons.in               |  6 ------
 tools/hotplug/Linux/systemd/Makefile                   |  1 -
 tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in | 12 ------------
 tools/libs/store/Makefile                              |  1 -
 tools/xenstore/.gdbinit                                |  4 ----
 tools/xenstore/Makefile                                |  4 ----
 tools/xenstore/Makefile.common                         |  1 -
 tools/xenstore/xs_lib.c                                | 11 +++++------
 14 files changed, 6 insertions(+), 54 deletions(-)

diff --git a/config/Paths.mk.in b/config/Paths.mk.in
index 416fc7aab9..44bab1d748 100644
--- a/config/Paths.mk.in
+++ b/config/Paths.mk.in
@@ -41,7 +41,6 @@ MAN8DIR                  := $(mandir)/man8
 XEN_RUN_DIR              := @XEN_RUN_DIR@
 XEN_LOG_DIR              := @XEN_LOG_DIR@
 XEN_LIB_DIR              := @XEN_LIB_DIR@
-XEN_LIB_STORED           := @XEN_LIB_STORED@
 XEN_RUN_STORED           := @XEN_RUN_STORED@
 
 CONFIG_DIR               := @CONFIG_DIR@
diff --git a/configure b/configure
index bb7f27ddad..b51174f2ef 100755
--- a/configure
+++ b/configure
@@ -603,7 +603,6 @@ INITD_DIR
 SHAREDIR
 XEN_LIB_DIR
 XEN_RUN_STORED
-XEN_LIB_STORED
 XEN_LOG_DIR
 XEN_RUN_DIR
 XENFIRMWAREDIR
@@ -2081,9 +2080,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-XEN_LIB_STORED=$localstatedir/lib/xenstored
-
-
 XEN_RUN_STORED=$rundir_path/xenstored
 
 
diff --git a/docs/configure b/docs/configure
index d4fced9858..f008ca0565 100755
--- a/docs/configure
+++ b/docs/configure
@@ -601,7 +601,6 @@ INITD_DIR
 SHAREDIR
 XEN_LIB_DIR
 XEN_RUN_STORED
-XEN_LIB_STORED
 XEN_LOG_DIR
 XEN_RUN_DIR
 XENFIRMWAREDIR
@@ -1984,9 +1983,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-XEN_LIB_STORED=$localstatedir/lib/xenstored
-
-
 XEN_RUN_STORED=$rundir_path/xenstored
 
 
diff --git a/m4/paths.m4 b/m4/paths.m4
index 826faada45..e4104bcce0 100644
--- a/m4/paths.m4
+++ b/m4/paths.m4
@@ -136,9 +136,6 @@ XEN_LOG_DIR=$localstatedir/log/xen
 AC_SUBST(XEN_LOG_DIR)
 AC_DEFINE_UNQUOTED([XEN_LOG_DIR], ["$XEN_LOG_DIR"], [Xen's log dir])
 
-XEN_LIB_STORED=$localstatedir/lib/xenstored
-AC_SUBST(XEN_LIB_STORED)
-
 XEN_RUN_STORED=$rundir_path/xenstored
 AC_SUBST(XEN_RUN_STORED)
 
diff --git a/tools/configure b/tools/configure
index 6199823f5a..ffe3f48901 100755
--- a/tools/configure
+++ b/tools/configure
@@ -725,7 +725,6 @@ INITD_DIR
 SHAREDIR
 XEN_LIB_DIR
 XEN_RUN_STORED
-XEN_LIB_STORED
 XEN_LOG_DIR
 XEN_RUN_DIR
 XENFIRMWAREDIR
@@ -4065,9 +4064,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-XEN_LIB_STORED=$localstatedir/lib/xenstored
-
-
 XEN_RUN_STORED=$rundir_path/xenstored
 
 
@@ -10085,7 +10081,7 @@ fi
 
 if test "x$systemd" = "xy"; then :
 
-    ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/var-lib-xenstored.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service"
+    ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service"
 
 
 fi
@@ -10967,7 +10963,6 @@ do
     "ocaml/xenstored/oxenstored.conf") CONFIG_FILES="$CONFIG_FILES ocaml/xenstored/oxenstored.conf" ;;
     "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
     "hotplug/Linux/systemd/proc-xen.mount") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/proc-xen.mount" ;;
-    "hotplug/Linux/systemd/var-lib-xenstored.mount") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/var-lib-xenstored.mount" ;;
     "hotplug/Linux/systemd/xen-init-dom0.service") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/xen-init-dom0.service" ;;
     "hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service" ;;
     "hotplug/Linux/systemd/xen-watchdog.service") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/xen-watchdog.service" ;;
diff --git a/tools/configure.ac b/tools/configure.ac
index 18e481d77e..3a2f6a2da9 100644
--- a/tools/configure.ac
+++ b/tools/configure.ac
@@ -482,7 +482,6 @@ AX_AVAILABLE_SYSTEMD()
 AS_IF([test "x$systemd" = "xy"], [
     AC_CONFIG_FILES([
     hotplug/Linux/systemd/proc-xen.mount
-    hotplug/Linux/systemd/var-lib-xenstored.mount
     hotplug/Linux/systemd/xen-init-dom0.service
     hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service
     hotplug/Linux/systemd/xen-watchdog.service
diff --git a/tools/hotplug/FreeBSD/rc.d/xencommons.in b/tools/hotplug/FreeBSD/rc.d/xencommons.in
index fddcce314c..7f7cda289f 100644
--- a/tools/hotplug/FreeBSD/rc.d/xencommons.in
+++ b/tools/hotplug/FreeBSD/rc.d/xencommons.in
@@ -14,7 +14,6 @@ export LD_LIBRARY_PATH
 
 name="xencommons"
 rcvar="xencommons_enable"
-start_precmd="xen_precmd"
 start_cmd="xen_startcmd"
 stop_cmd="xen_stop"
 status_cmd="xen_status"
@@ -30,11 +29,6 @@ XENSTORED_PIDFILE="@XEN_RUN_DIR@/xenstored.pid"
 load_rc_config $name
 : ${xencommons_enable:=no}
 
-xen_precmd()
-{
-	mkdir -p @XEN_LIB_STORED@ || exit 1
-}
-
 xen_startcmd()
 {
 	local time=0
diff --git a/tools/hotplug/Linux/systemd/Makefile b/tools/hotplug/Linux/systemd/Makefile
index 26df2a43b1..e29889156d 100644
--- a/tools/hotplug/Linux/systemd/Makefile
+++ b/tools/hotplug/Linux/systemd/Makefile
@@ -4,7 +4,6 @@ include $(XEN_ROOT)/tools/Rules.mk
 XEN_SYSTEMD_MODULES := xen.conf
 
 XEN_SYSTEMD_MOUNT := proc-xen.mount
-XEN_SYSTEMD_MOUNT += var-lib-xenstored.mount
 
 XEN_SYSTEMD_SERVICE := xenstored.service
 XEN_SYSTEMD_SERVICE += xenconsoled.service
diff --git a/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in b/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in
deleted file mode 100644
index 11a7d50edc..0000000000
--- a/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in
+++ /dev/null
@@ -1,12 +0,0 @@
-[Unit]
-Description=mount xenstore file system
-Requires=proc-xen.mount
-After=proc-xen.mount
-ConditionPathExists=/proc/xen/capabilities
-RefuseManualStop=true
-
-[Mount]
-What=xenstore
-Where=@XEN_LIB_STORED@
-Type=tmpfs
-Options=mode=755
diff --git a/tools/libs/store/Makefile b/tools/libs/store/Makefile
index 2334c953bb..3557a8c76d 100644
--- a/tools/libs/store/Makefile
+++ b/tools/libs/store/Makefile
@@ -18,7 +18,6 @@ include ../libs.mk
 # Include configure output (config.h)
 CFLAGS += -include $(XEN_ROOT)/tools/config.h
 CFLAGS += $(CFLAGS_libxentoolcore)
-CFLAGS += -DXEN_LIB_STORED="\"$(XEN_LIB_STORED)\""
 CFLAGS += -DXEN_RUN_STORED="\"$(XEN_RUN_STORED)\""
 
 vpath xs_lib.c $(XEN_ROOT)/tools/xenstore
diff --git a/tools/xenstore/.gdbinit b/tools/xenstore/.gdbinit
deleted file mode 100644
index 9a71b20ac4..0000000000
--- a/tools/xenstore/.gdbinit
+++ /dev/null
@@ -1,4 +0,0 @@
-set environment XENSTORED_RUNDIR=testsuite/tmp
-set environment XENSTORED_ROOTDIR=testsuite/tmp
-handle SIGUSR1 noprint nostop
-handle SIGPIPE noprint nostop
diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile
index 1b66190cc5..ce7a68178f 100644
--- a/tools/xenstore/Makefile
+++ b/tools/xenstore/Makefile
@@ -69,7 +69,6 @@ install: all
 	$(INSTALL_DIR) $(DESTDIR)$(bindir)
 ifeq ($(XENSTORE_XENSTORED),y)
 	$(INSTALL_DIR) $(DESTDIR)$(sbindir)
-	$(INSTALL_DIR) $(DESTDIR)$(XEN_LIB_STORED)
 	$(INSTALL_PROG) xenstored $(DESTDIR)$(sbindir)
 endif
 	$(INSTALL_PROG) xenstore-control $(DESTDIR)$(bindir)
@@ -85,9 +84,6 @@ uninstall:
 	rm -f $(DESTDIR)$(bindir)/xenstore-control
 ifeq ($(XENSTORE_XENSTORED),y)
 	rm -f $(DESTDIR)$(sbindir)/xenstored
-	if [ -d $(DESTDIR)$(XEN_LIB_STORED) ]; then \
-		rmdir --ignore-fail-on-non-empty $(DESTDIR)$(XEN_LIB_STORED); \
-	fi
 endif
 	if [ -d $(DESTDIR)$(includedir)/xenstore-compat ]; then \
 		rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/xenstore-compat; \
diff --git a/tools/xenstore/Makefile.common b/tools/xenstore/Makefile.common
index ddbac052ac..b18f95c103 100644
--- a/tools/xenstore/Makefile.common
+++ b/tools/xenstore/Makefile.common
@@ -16,7 +16,6 @@ CFLAGS += $(CFLAGS_libxenevtchn)
 CFLAGS += $(CFLAGS_libxenctrl)
 CFLAGS += $(CFLAGS_libxenguest)
 CFLAGS += $(CFLAGS_libxentoolcore)
-CFLAGS += -DXEN_LIB_STORED="\"$(XEN_LIB_STORED)\""
 CFLAGS += -DXEN_RUN_STORED="\"$(XEN_RUN_STORED)\""
 
 ifdef CONFIG_STUBDOM
diff --git a/tools/xenstore/xs_lib.c b/tools/xenstore/xs_lib.c
index 10fa4c3ad0..b9941c567c 100644
--- a/tools/xenstore/xs_lib.c
+++ b/tools/xenstore/xs_lib.c
@@ -26,18 +26,17 @@
 
 /* Common routines for the Xen store daemon and client library. */
 
-const char *xs_daemon_rootdir(void)
-{
-	char *s = getenv("XENSTORED_ROOTDIR");
-	return (s ? s : XEN_LIB_STORED);
-}
-
 const char *xs_daemon_rundir(void)
 {
 	char *s = getenv("XENSTORED_RUNDIR");
 	return (s ? s : XEN_RUN_STORED);
 }
 
+const char *xs_daemon_rootdir(void)
+{
+	return xs_daemon_rundir();
+}
+
 static const char *xs_daemon_path(void)
 {
 	static char buf[PATH_MAX];
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 11:11:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 11:11:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435801.689586 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBeY-00088a-Ij; Wed, 02 Nov 2022 11:11:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435801.689586; Wed, 02 Nov 2022 11:11:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBeY-00088S-G7; Wed, 02 Nov 2022 11:11:26 +0000
Received: by outflank-mailman (input) for mailman id 435801;
 Wed, 02 Nov 2022 11:11:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeX-00088F-6x
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeX-0008DL-6E
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBeX-0006Hv-5J
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:11:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=OvtQzNobNMYJGrD1M/ftOf462AAftyqr8B+S65UkLzA=; b=itxwaRmwnYVXcl7GcY7F4bO9gR
	u+eKWuZVJlHwDtKKaVT+244xPKxFzOgj3IKA+EXicSgnpb7f++fcCoYxX78qKg1L3TK52dXsU5D6H
	dENkD7FTaOBzAQusE67s+UEBObC/bQsDA2gXU1zWlAy4rrIv3z87yJ7YrbyYd1lczm1U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging] tools/xenstore: call remove_domid_from_perm() for special nodes
Message-Id: <E1oqBeX-0006Hv-5J@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 11:11:25 +0000

commit 0751a75e3996cf6efd3925a90b4776660d8df2bc
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 2 12:08:22 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:08:22 2022 +0100

    tools/xenstore: call remove_domid_from_perm() for special nodes
    
    When destroying a domain, any stale permissions of the domain must be
    removed from the special nodes "@...", too. This was not done in the
    fix for XSA-322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/xenstore/xenstored_domain.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 84b7817cd5..aa86892fed 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -227,6 +227,27 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static void remove_domid_from_perm(struct node_perms *perms,
+				   struct domain *domain)
+{
+	unsigned int cur, new;
+
+	if (perms->p[0].id == domain->domid)
+		perms->p[0].id = priv_domid;
+
+	for (cur = new = 1; cur < perms->num; cur++) {
+		if (perms->p[cur].id == domain->domid)
+			continue;
+
+		if (new != cur)
+			perms->p[new] = perms->p[cur];
+
+		new++;
+	}
+
+	perms->num = new;
+}
+
 static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
 				  struct node *node, void *arg)
 {
@@ -277,6 +298,9 @@ static void domain_tree_remove(struct domain *domain)
 			syslog(LOG_ERR,
 			       "error when looking for orphaned nodes\n");
 	}
+
+	remove_domid_from_perm(&dom_release_perms, domain);
+	remove_domid_from_perm(&dom_introduce_perms, domain);
 }
 
 static int destroy_domain(void *_domain)
--
generated by git-patchbot for /home/xen/git/xen.git#staging


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 11:22:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 11:22:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435802.689590 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBor-0001BL-Ai; Wed, 02 Nov 2022 11:22:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435802.689590; Wed, 02 Nov 2022 11:22:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBor-0001BC-6k; Wed, 02 Nov 2022 11:22:05 +0000
Received: by outflank-mailman (input) for mailman id 435802;
 Wed, 02 Nov 2022 11:22:04 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBoq-0001Aq-44
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:22:04 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBoq-0008Qa-0Y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:22:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBop-0006jj-Vn
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:22:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8jKMdgmO7xhYO9rB3I1IJBtKZLG0AUggLnmscnjaRgY=; b=u2hhtcNOboLXNQkL56CWc5erAg
	3ACyVGkw1aaQts7rKiObL0izhavptpm2ziSHDAZF7r/2k8iMIwN8tnbQaxtYJLsfQNtZs5NokZQpl
	oNGiQOWGizpEHQPTyx47nG6fJjNOOWDACLQZ2EHcwMm1p38MHh95a0KsyZ9s1lY5sD6E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.14] x86/shadow: drop (replace) bogus assertions
Message-Id: <E1oqBop-0006jj-Vn@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 11:22:03 +0000

commit 6222bb8bd76a0f21048c852acd2542fa2494a907
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Wed Nov 2 12:12:30 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:12:30 2022 +0100

    x86/shadow: drop (replace) bogus assertions
    
    The addition of a call to shadow_blow_tables() from shadow_teardown()
    has resulted in the "no vcpus" related assertion becoming triggerable:
    If domain_create() fails with at least one page successfully allocated
    in the course of shadow_enable(), or if domain_create() succeeds and
    the domain is then killed without ever invoking XEN_DOMCTL_max_vcpus.
    Note that in-tree tests (test-resource and test-tsx) do exactly the
    latter of these two.
    
    The assertion's comment was bogus anyway: Shadow mode has been getting
    enabled before allocation of vCPU-s for quite some time. Convert the
    assertion to a conditional: As long as there are no vCPU-s, there's
    nothing to blow away.
    
    Fixes: e7aa55c0aab3 ("x86/p2m: free the paging memory pool preemptively")
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    
    A similar assertion/comment pair exists in _shadow_prealloc(); the
    comment is similarly bogus, and the assertion could in principle trigger
    e.g. when shadow_alloc_p2m_page() is called early enough. Replace those
    at the same time by a similar early return, here indicating failure to
    the caller (which will generally lead to the domain being crashed in
    shadow_prealloc()).
    
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Roger Pau Monné <roger.pau@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    master commit: a92dc2bb30ba65ae25d2f417677eb7ef9a6a0fef
    master date: 2022-10-24 15:46:11 +0200
---
 xen/arch/x86/mm/shadow/common.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index ba2ef80778..e803ac7866 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -942,8 +942,9 @@ static bool __must_check _shadow_prealloc(struct domain *d, unsigned int pages)
         /* No reclaim when the domain is dying, teardown will take care of it. */
         return false;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to reclaim when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return false;
 
     /* Stage one: walk the list of pinned pages, unpinning them */
     perfc_incr(shadow_prealloc_1);
@@ -1031,8 +1032,9 @@ static void shadow_blow_tables(struct domain *d)
     mfn_t smfn;
     int i;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to do when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return;
 
     /* Pass one: unpin all pinned pages */
     foreach_pinned_shadow(d, sp, t)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 11:22:15 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 11:22:15 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435803.689593 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBp1-0001DM-B9; Wed, 02 Nov 2022 11:22:15 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435803.689593; Wed, 02 Nov 2022 11:22:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqBp1-0001DF-8V; Wed, 02 Nov 2022 11:22:15 +0000
Received: by outflank-mailman (input) for mailman id 435803;
 Wed, 02 Nov 2022 11:22:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBp0-0001D5-A4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:22:14 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBp0-0008Qo-9E
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:22:14 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqBp0-0006kl-8F
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 11:22:14 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Rvr2UCntKl6wN2cIiaytILFebcmLAx1zPeiHQv64o4c=; b=tj3JQTuOhO2SHwPP67ESFPWJG4
	6xic0DAV1/Fju8YNFI2gyfO7drEghIuf+rP0513cXJ3Pm6zIk2yewZTg3HzZ0nBWfaf9Hobm7VaNv
	MzLUMt/O/jd4qDJEJGLPK90fY9Pxi2zvX566y0a73s2tgIOc1ckm+FbOl104Jn2PGtvI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen staging-4.13] x86/shadow: drop (replace) bogus assertions
Message-Id: <E1oqBp0-0006kl-8F@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 11:22:14 +0000

commit 4d753ccf9ddf12332435f50d88e8cf0161e7a5b3
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Wed Nov 2 12:13:48 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:13:48 2022 +0100

    x86/shadow: drop (replace) bogus assertions
    
    The addition of a call to shadow_blow_tables() from shadow_teardown()
    has resulted in the "no vcpus" related assertion becoming triggerable:
    If domain_create() fails with at least one page successfully allocated
    in the course of shadow_enable(), or if domain_create() succeeds and
    the domain is then killed without ever invoking XEN_DOMCTL_max_vcpus.
    Note that in-tree tests (test-resource and test-tsx) do exactly the
    latter of these two.
    
    The assertion's comment was bogus anyway: Shadow mode has been getting
    enabled before allocation of vCPU-s for quite some time. Convert the
    assertion to a conditional: As long as there are no vCPU-s, there's
    nothing to blow away.
    
    Fixes: e7aa55c0aab3 ("x86/p2m: free the paging memory pool preemptively")
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    
    A similar assertion/comment pair exists in _shadow_prealloc(); the
    comment is similarly bogus, and the assertion could in principle trigger
    e.g. when shadow_alloc_p2m_page() is called early enough. Replace those
    at the same time by a similar early return, here indicating failure to
    the caller (which will generally lead to the domain being crashed in
    shadow_prealloc()).
    
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Roger Pau Monné <roger.pau@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    master commit: a92dc2bb30ba65ae25d2f417677eb7ef9a6a0fef
    master date: 2022-10-24 15:46:11 +0200
---
 xen/arch/x86/mm/shadow/common.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index e6af359579..cf1743488a 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -911,8 +911,9 @@ static bool __must_check _shadow_prealloc(struct domain *d, unsigned int pages)
         /* No reclaim when the domain is dying, teardown will take care of it. */
         return false;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to reclaim when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return false;
 
     /* Stage one: walk the list of pinned pages, unpinning them */
     perfc_incr(shadow_prealloc_1);
@@ -1000,8 +1001,9 @@ static void shadow_blow_tables(struct domain *d)
     mfn_t smfn;
     int i;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to do when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return;
 
     /* Pass one: unpin all pinned pages */
     foreach_pinned_shadow(d, sp, t)
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:11:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:11:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435872.689687 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCaF-0004YV-Em; Wed, 02 Nov 2022 12:11:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435872.689687; Wed, 02 Nov 2022 12:11:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCaF-0004YM-A1; Wed, 02 Nov 2022 12:11:03 +0000
Received: by outflank-mailman (input) for mailman id 435872;
 Wed, 02 Nov 2022 12:11:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaE-0004YC-28
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaD-0000oT-Vt
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaD-0001Er-Uq
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=YsBHHXcimGPRnxWP0sZ8GKGx1HDifasvqtghKtj/p9k=; b=ovwS/mVCX0UgOosaJHAhm3GrTx
	3g3ZTIL3O26fNLmwbafCY7LTdSXau7pX98gQZYRPWH/hx75cTU3+DixzkDb40F1akUW+zHnw4PVXq
	alb1c2GslqD+8fI+eBCglqyUvtz0GzPqdxxw0HmdV61denX/P1W7XtcBcAn6O4+SkrIs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] x86/vmx: Revert "VMX: use a single, global APIC access page"
Message-Id: <E1oqCaD-0001Er-Uq@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:11:01 +0000

commit 3b5beaf49033cddf4b2cc4e4d391b966f4203471
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Wed Aug 24 14:16:44 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    x86/vmx: Revert "VMX: use a single, global APIC access page"
    
    The claim "No accesses would ever go to this page." is false.  A consequence
    of how Intel's APIC Acceleration works, and Xen's choice to have per-domain
    P2Ms (rather than per-vCPU P2Ms) means that the APIC page is fully read-write
    to any vCPU which is not in xAPIC mode.
    
    This reverts commit 58850b9074d3e7affdf3bc94c84e417ecfa4d165.
    
    This is XSA-412 / CVE-2022-42327.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/hvm/vmx/vmx.c              | 59 ++++++++++++++++++++++++---------
 xen/arch/x86/include/asm/hvm/vmx/vmcs.h |  1 +
 xen/arch/x86/include/asm/mm.h           | 20 +----------
 xen/arch/x86/mm/shadow/set.c            |  8 -----
 xen/arch/x86/mm/shadow/types.h          |  7 ----
 5 files changed, 46 insertions(+), 49 deletions(-)

diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 17e103188a..e624b415c9 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -66,7 +66,8 @@ boolean_param("force-ept", opt_force_ept);
 static void cf_check vmx_ctxt_switch_from(struct vcpu *v);
 static void cf_check vmx_ctxt_switch_to(struct vcpu *v);
 
-static int alloc_vlapic_mapping(void);
+static int  vmx_alloc_vlapic_mapping(struct domain *d);
+static void vmx_free_vlapic_mapping(struct domain *d);
 static void vmx_install_vlapic_mapping(struct vcpu *v);
 static void cf_check vmx_update_guest_cr(
     struct vcpu *v, unsigned int cr, unsigned int flags);
@@ -79,8 +80,6 @@ static int cf_check vmx_msr_write_intercept(
     unsigned int msr, uint64_t msr_content);
 static void cf_check vmx_invlpg(struct vcpu *v, unsigned long linear);
 
-static mfn_t __read_mostly apic_access_mfn = INVALID_MFN_INITIALIZER;
-
 /* Values for domain's ->arch.hvm_domain.pi_ops.flags. */
 #define PI_CSW_FROM (1u << 0)
 #define PI_CSW_TO   (1u << 1)
@@ -404,6 +403,7 @@ static int cf_check vmx_domain_initialise(struct domain *d)
         .to   = vmx_ctxt_switch_to,
         .tail = vmx_do_resume,
     };
+    int rc;
 
     d->arch.ctxt_switch = &csw;
 
@@ -413,15 +413,24 @@ static int cf_check vmx_domain_initialise(struct domain *d)
      */
     d->arch.hvm.vmx.exec_sp = is_hardware_domain(d) || opt_ept_exec_sp;
 
+    if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 )
+        return rc;
+
     return 0;
 }
 
+static void cf_check vmx_domain_relinquish_resources(struct domain *d)
+{
+    vmx_free_vlapic_mapping(d);
+}
+
 static void cf_check domain_creation_finished(struct domain *d)
 {
     gfn_t gfn = gaddr_to_gfn(APIC_DEFAULT_PHYS_BASE);
+    mfn_t apic_access_mfn = d->arch.hvm.vmx.apic_access_mfn;
     bool ipat;
 
-    if ( mfn_eq(apic_access_mfn, INVALID_MFN) )
+    if ( mfn_eq(apic_access_mfn, _mfn(0)) )
         return;
 
     ASSERT(epte_get_entry_emt(d, gfn, apic_access_mfn, 0, &ipat,
@@ -2510,6 +2519,7 @@ static struct hvm_function_table __initdata_cf_clobber vmx_function_table = {
     .cpu_up_prepare       = vmx_cpu_up_prepare,
     .cpu_dead             = vmx_cpu_dead,
     .domain_initialise    = vmx_domain_initialise,
+    .domain_relinquish_resources = vmx_domain_relinquish_resources,
     .domain_creation_finished = domain_creation_finished,
     .vcpu_initialise      = vmx_vcpu_initialise,
     .vcpu_destroy         = vmx_vcpu_destroy,
@@ -2760,7 +2770,7 @@ const struct hvm_function_table * __init start_vmx(void)
 {
     set_in_cr4(X86_CR4_VMXE);
 
-    if ( vmx_vmcs_init() || alloc_vlapic_mapping() )
+    if ( vmx_vmcs_init() )
     {
         printk("VMX: failed to initialise.\n");
         return NULL;
@@ -3331,36 +3341,55 @@ gp_fault:
     return X86EMUL_EXCEPTION;
 }
 
-static int __init alloc_vlapic_mapping(void)
+static int vmx_alloc_vlapic_mapping(struct domain *d)
 {
     struct page_info *pg;
     mfn_t mfn;
 
-    if ( !cpu_has_vmx_virtualize_apic_accesses )
+    if ( !has_vlapic(d) || !cpu_has_vmx_virtualize_apic_accesses )
         return 0;
 
-    pg = alloc_domheap_page(NULL, 0);
+    pg = alloc_domheap_page(d, MEMF_no_refcount);
     if ( !pg )
         return -ENOMEM;
 
-    /*
-     * Signal to shadow code that this page cannot be refcounted. This also
-     * makes epte_get_entry_emt() recognize this page as "special".
-     */
-    page_suppress_refcounting(pg);
+    if ( !get_page_and_type(pg, d, PGT_writable_page) )
+    {
+        /*
+         * The domain can't possibly know about this page yet, so failure
+         * here is a clear indication of something fishy going on.
+         */
+        domain_crash(d);
+        return -ENODATA;
+    }
 
     mfn = page_to_mfn(pg);
     clear_domain_page(mfn);
-    apic_access_mfn = mfn;
+    d->arch.hvm.vmx.apic_access_mfn = mfn;
 
     return 0;
 }
 
+static void vmx_free_vlapic_mapping(struct domain *d)
+{
+    mfn_t mfn = d->arch.hvm.vmx.apic_access_mfn;
+
+    d->arch.hvm.vmx.apic_access_mfn = _mfn(0);
+    if ( !mfn_eq(mfn, _mfn(0)) )
+    {
+        struct page_info *pg = mfn_to_page(mfn);
+
+        put_page_alloc_ref(pg);
+        put_page_and_type(pg);
+    }
+}
+
 static void vmx_install_vlapic_mapping(struct vcpu *v)
 {
+    mfn_t apic_access_mfn = v->domain->arch.hvm.vmx.apic_access_mfn;
     paddr_t virt_page_ma, apic_page_ma;
 
-    if ( mfn_eq(apic_access_mfn, INVALID_MFN) )
+    if ( mfn_eq(apic_access_mfn, _mfn(0)) )
         return;
 
     ASSERT(cpu_has_vmx_virtualize_apic_accesses);
diff --git a/xen/arch/x86/include/asm/hvm/vmx/vmcs.h b/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
index 9119aa8536..75f9928abf 100644
--- a/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
+++ b/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
@@ -58,6 +58,7 @@ struct ept_data {
 #define _VMX_DOMAIN_PML_ENABLED    0
 #define VMX_DOMAIN_PML_ENABLED     (1ul << _VMX_DOMAIN_PML_ENABLED)
 struct vmx_domain {
+    mfn_t apic_access_mfn;
     /* VMX_DOMAIN_* */
     unsigned int status;
 
diff --git a/xen/arch/x86/include/asm/mm.h b/xen/arch/x86/include/asm/mm.h
index 0fc826de46..d723c7c38f 100644
--- a/xen/arch/x86/include/asm/mm.h
+++ b/xen/arch/x86/include/asm/mm.h
@@ -83,7 +83,7 @@
 #define PGC_state_offlined  PG_mask(2, 6)
 #define PGC_state_free      PG_mask(3, 6)
 #define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
-/* Page is not reference counted (see below for caveats) */
+/* Page is not reference counted */
 #define _PGC_extra        PG_shift(7)
 #define PGC_extra         PG_mask(1, 7)
 
@@ -375,24 +375,6 @@ void zap_ro_mpt(mfn_t mfn);
 
 bool is_iomem_page(mfn_t mfn);
 
-/*
- * Pages with no owner which may get passed to functions wanting to
- * refcount them can be marked PGC_extra to bypass this refcounting (which
- * would fail due to the lack of an owner).
- *
- * (For pages with owner PGC_extra has different meaning.)
- */
-static inline void page_suppress_refcounting(struct page_info *pg)
-{
-   ASSERT(!page_get_owner(pg));
-   pg->count_info |= PGC_extra;
-}
-
-static inline bool page_refcounting_suppressed(const struct page_info *pg)
-{
-    return !page_get_owner(pg) && (pg->count_info & PGC_extra);
-}
-
 struct platform_bad_page {
     unsigned long mfn;
     unsigned int order;
diff --git a/xen/arch/x86/mm/shadow/set.c b/xen/arch/x86/mm/shadow/set.c
index 87e9c6eeb2..bd6c68b547 100644
--- a/xen/arch/x86/mm/shadow/set.c
+++ b/xen/arch/x86/mm/shadow/set.c
@@ -101,14 +101,6 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type)
         owner = page_get_owner(pg);
     }
 
-    /*
-     * Check whether refcounting is suppressed on this page. For example,
-     * VMX'es APIC access MFN is just a surrogate page.  It doesn't actually
-     * get accessed, and hence there's no need to refcount it.
-     */
-    if ( pg && page_refcounting_suppressed(pg) )
-        return 0;
-
     if ( owner == dom_io )
         owner = NULL;
 
diff --git a/xen/arch/x86/mm/shadow/types.h b/xen/arch/x86/mm/shadow/types.h
index 6970e7d6ea..814a401853 100644
--- a/xen/arch/x86/mm/shadow/types.h
+++ b/xen/arch/x86/mm/shadow/types.h
@@ -276,16 +276,9 @@ int shadow_set_l4e(struct domain *d, shadow_l4e_t *sl4e,
 static void inline
 shadow_put_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
 {
-    mfn_t mfn = shadow_l1e_get_mfn(sl1e);
-
     if ( !shadow_mode_refcounts(d) )
         return;
 
-    if ( mfn_valid(mfn) &&
-         /* See the respective comment in shadow_get_page_from_l1e(). */
-         page_refcounting_suppressed(mfn_to_page(mfn)) )
-        return;
-
     put_page_from_l1e(sl1e, d);
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:11:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:11:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435873.689692 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCaP-0004bC-G8; Wed, 02 Nov 2022 12:11:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435873.689692; Wed, 02 Nov 2022 12:11:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCaP-0004b5-Bl; Wed, 02 Nov 2022 12:11:13 +0000
Received: by outflank-mailman (input) for mailman id 435873;
 Wed, 02 Nov 2022 12:11:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaO-0004at-47
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaO-0000ob-3Q
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaO-0001Fn-2F
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=6+W52qIuLd+azxTbhPcs+uNukRWeah9AjwF8FWYqAmc=; b=lKoxpjM0Mlm6+oXMqRY5SftNTR
	pheVaCZoY6/EepTLegp8ODsH4BNpFH4RPDgF31WmY9/ooQi4uCJcZkCBRnjEbpFcq9/yV2vEkkfxg
	aLopmKLTUNfyeYwS+NUDQ0SJpK1nCqxBFIpOHZiRW6m8coTTz6SmyddIzXW6gcqo40KA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: create_node: Don't defer work to undo any changes on failure
Message-Id: <E1oqCaO-0001Fn-2F@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:11:12 +0000

commit 1cd3cc7ea27cda7640a8d895e09617b61c265697
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: create_node: Don't defer work to undo any changes on failure
    
    XSA-115 extended destroy_node() to update the node accounting for the
    connection. The implementation is assuming the connection is the parent
    of the node, however all the nodes are allocated using a separate context
    (see process_message()). This will result to crash (or corrupt) xenstored
    as the pointer is wrongly used.
    
    In case of an error, any changes to the database or update to the
    accounting will now be reverted in create_node() by calling directly
    destroy_node(). This has the nice advantage to remove the loop to unset
    the destructors in case of success.
    
    Take the opportunity to free the nodes right now as they are not
    going to be reachable (the function returns NULL) and are just wasting
    resources.
    
    This is XSA-414 / CVE-2022-42309.
    
    Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation")
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
---
 tools/xenstore/xenstored_core.c | 47 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 8867f93431..c30d14cbf2 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1084,9 +1084,8 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(void *_node)
+static int destroy_node(struct connection *conn, struct node *node)
 {
-	struct node *node = _node;
 	TDB_DATA key;
 
 	if (streq(node->name, "/"))
@@ -1095,7 +1094,7 @@ static int destroy_node(void *_node)
 	set_tdb_key(node->name, &key);
 	tdb_delete(tdb_ctx, key);
 
-	domain_entry_dec(talloc_parent(node), node);
+	domain_entry_dec(conn, node);
 
 	return 0;
 }
@@ -1104,7 +1103,8 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 				const char *name,
 				void *data, unsigned int datalen)
 {
-	struct node *node, *i;
+	struct node *node, *i, *j;
+	int ret;
 
 	node = construct_node(conn, ctx, name);
 	if (!node)
@@ -1126,23 +1126,40 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 		/* i->parent is set for each new node, so check quota. */
 		if (i->parent &&
 		    domain_entry(conn) >= quota_nb_entry_per_domain) {
-			errno = ENOSPC;
-			return NULL;
+			ret = ENOSPC;
+			goto err;
 		}
-		if (write_node(conn, i, false))
-			return NULL;
 
-		/* Account for new node, set destructor for error case. */
-		if (i->parent) {
+		ret = write_node(conn, i, false);
+		if (ret)
+			goto err;
+
+		/* Account for new node */
+		if (i->parent)
 			domain_entry_inc(conn, i);
-			talloc_set_destructor(i, destroy_node);
-		}
 	}
 
-	/* OK, now remove destructors so they stay around */
-	for (i = node; i->parent; i = i->parent)
-		talloc_set_destructor(i, NULL);
 	return node;
+
+err:
+	/*
+	 * We failed to update TDB for some of the nodes. Undo any work that
+	 * have already been done.
+	 */
+	for (j = node; j != i; j = j->parent)
+		destroy_node(conn, j);
+
+	/* We don't need to keep the nodes around, so free them. */
+	i = node;
+	while (i) {
+		j = i;
+		i = i->parent;
+		talloc_free(j);
+	}
+
+	errno = ret;
+
+	return NULL;
 }
 
 /* path, data... */
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:11:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:11:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435874.689694 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCaZ-0004eF-Ga; Wed, 02 Nov 2022 12:11:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435874.689694; Wed, 02 Nov 2022 12:11:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCaZ-0004e7-DT; Wed, 02 Nov 2022 12:11:23 +0000
Received: by outflank-mailman (input) for mailman id 435874;
 Wed, 02 Nov 2022 12:11:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaY-0004dz-7S
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaY-0000pC-6l
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCaY-0001GS-5y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Lwk/Vw/wVgSHJkzqfOm4hnMOlAReztJJge/6LMIFk+g=; b=hdF+cHPo/iDsQCBwd5D10+LW7S
	JtmqsqkSkWSDFJzqDFuBC46TunJOVpFbLYk7GZb1w+qhxg5DvDzl2AEjNhjaXdnFv4foWRBbpkamc
	3f0KEsz80vG9bnLcZEamJvzUpxyrZlUSqrEOn2t/V7nIwW3mocke2UkZ3zJdHUiWwnBw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: Fail a transaction if it is not possible to create a node
Message-Id: <E1oqCaY-0001GS-5y@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:11:22 +0000

commit 5d71766bd1a4a3a8b2fe952ca2be80e02fe48f34
Author:     Julien Grall <jgrall@amazon.com>
AuthorDate: Tue Sep 13 07:35:06 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: Fail a transaction if it is not possible to create a node
    
    Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved
    out from copying the entire database everytime a new transaction is
    opened to track the list of nodes changed.
    
    The content of all the nodes accessed during a transaction will be
    temporarily stored in TDB using a different key.
    
    The function create_node() may write/update multiple nodes if the child
    doesn't exist. In case of a failure, the function will revert any
    changes (this include any update to TDB). Unfortunately, the function
    which reverts the changes (i.e. destroy_node()) will not use the correct
    key to delete any update or even request the transaction to fail.
    
    This means that if a client decide to go ahead with committing the
    transaction, orphan nodes will be created because they were not linked
    to an existing node (create_node() will write the nodes backwards).
    
    Once some nodes have been partially updated in a transaction, it is not
    easily possible to undo any changes. So rather than continuing and hit
    weird issue while committing, it is much saner to fail the transaction.
    
    This will have an impact on any client that decides to commit even if it
    can't write a node. Although, it is not clear why a normal client would
    want to do that...
    
    Lastly, update destroy_node() to use the correct key for deleting the
    node. Rather than recreating it (this will allocate memory and
    therefore fail), stash the key in the structure node.
    
    This is XSA-415 / CVE-2022-42310.
    
    Signed-off-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
---
 tools/xenstore/xenstored_core.c        | 23 +++++++++++++++--------
 tools/xenstore/xenstored_core.h        |  2 ++
 tools/xenstore/xenstored_transaction.c |  5 +++++
 tools/xenstore/xenstored_transaction.h |  3 +++
 4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index c30d14cbf2..55b79e4c03 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -562,15 +562,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	return 0;
 }
 
+/*
+ * Write the node. If the node is written, caller can find the key used in
+ * node->key. This can later be used if the change needs to be reverted.
+ */
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_WRITE, &key))
+	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &key, node, no_quota_check);
+	return write_node_raw(conn, &node->key, node, no_quota_check);
 }
 
 unsigned int perm_for_conn(struct connection *conn,
@@ -1086,16 +1088,21 @@ nomem:
 
 static int destroy_node(struct connection *conn, struct node *node)
 {
-	TDB_DATA key;
-
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
-	set_tdb_key(node->name, &key);
-	tdb_delete(tdb_ctx, key);
+	tdb_delete(tdb_ctx, node->key);
 
 	domain_entry_dec(conn, node);
 
+	/*
+	 * It is not possible to easily revert the changes in a transaction.
+	 * So if the failure happens in a transaction, mark it as fail to
+	 * prevent any commit.
+	 */
+	if ( conn->transaction )
+		fail_transaction(conn->transaction);
+
 	return 0;
 }
 
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 742812a974..7d0fe77e79 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -155,6 +155,8 @@ struct node_perms {
 
 struct node {
 	const char *name;
+	/* Key used to update TDB */
+	TDB_DATA key;
 
 	/* Parent (optional) */
 	struct node *parent;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index cd07fb0f21..faf6c930e4 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid)
 	list_add_tail(&d->list, &trans->changed_domains);
 }
 
+void fail_transaction(struct transaction *trans)
+{
+	trans->fail = true;
+}
+
 void conn_delete_all_transactions(struct connection *conn)
 {
 	struct transaction *trans;
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 43a162bea3..14062730e3 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node,
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
 
+/* Mark the transaction as failed. This will prevent it to be committed. */
+void fail_transaction(struct transaction *trans);
+
 void conn_delete_all_transactions(struct connection *conn);
 int check_transactions(struct hashtable *hash);
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:11:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:11:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435875.689697 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCaj-0004iP-ID; Wed, 02 Nov 2022 12:11:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435875.689697; Wed, 02 Nov 2022 12:11:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCaj-0004iH-FB; Wed, 02 Nov 2022 12:11:33 +0000
Received: by outflank-mailman (input) for mailman id 435875;
 Wed, 02 Nov 2022 12:11:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCai-0004i5-CO
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCai-0000pM-Bk
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCai-0001H4-9B
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Gx4RZCC2B7jsAZZnasEe44poyvj/qpD2uW/WH4nZsr8=; b=rFbdPPbXpt4Yyj0jjA27sS6iIe
	3i+xZbxjQnHlKNZqc84IbxdMcTuQ2xPWyQBuZuuFCrj5r5xwaX7r7MmWaUoT7AfbP++uPCxcmzonh
	l1m60JPl1WxlOzkEREV5512C0lS4Wh5iEIUEKnZ8mgyJCiEKJVHSmo4TE6RHEO6G1yMc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: split up send_reply()
Message-Id: <E1oqCai-0001H4-9B@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:11:32 +0000

commit 9bfde319dbac2a1321898d2f75a3f075c3eb7b32
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: split up send_reply()
    
    Today send_reply() is used for both, normal request replies and watch
    events.
    
    Split it up into send_reply() and send_event(). This will be used to
    add some event specific handling.
    
    add_event() can be merged into send_event(), removing the need for an
    intermediate memory allocation.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c  | 74 ++++++++++++++++++++++++----------------
 tools/xenstore/xenstored_core.h  |  1 +
 tools/xenstore/xenstored_watch.c | 39 ++++-----------------
 3 files changed, 52 insertions(+), 62 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 55b79e4c03..ed742d9dfc 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -763,49 +763,32 @@ static void send_error(struct connection *conn, int error)
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata = conn->in;
+
+	assert(type != XS_WATCH_EVENT);
 
 	if ( len > XENSTORE_PAYLOAD_MAX ) {
 		send_error(conn, E2BIG);
 		return;
 	}
 
-	/* Replies reuse the request buffer, events need a new one. */
-	if (type != XS_WATCH_EVENT) {
-		bdata = conn->in;
-		/* Drop asynchronous responses, e.g. errors for watch events. */
-		if (!bdata)
-			return;
-		bdata->inhdr = true;
-		bdata->used = 0;
-		conn->in = NULL;
-	} else {
-		/* Message is a child of the connection for auto-cleanup. */
-		bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+	bdata->inhdr = true;
+	bdata->used = 0;
 
-		/*
-		 * Allocation failure here is unfortunate: we have no way to
-		 * tell anybody about it.
-		 */
-		if (!bdata)
-			return;
-	}
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
-	else
+	else {
 		bdata->buffer = talloc_array(bdata, char, len);
-	if (!bdata->buffer) {
-		if (type == XS_WATCH_EVENT) {
-			/* Same as above: no way to tell someone. */
-			talloc_free(bdata);
+		if (!bdata->buffer) {
+			send_error(conn, ENOMEM);
 			return;
 		}
-		/* re-establish request buffer for sending ENOMEM. */
-		conn->in = bdata;
-		send_error(conn, ENOMEM);
-		return;
 	}
 
+	conn->in = NULL;
+
 	/* Update relevant header fields and fill in the message body. */
 	bdata->hdr.msg.type = type;
 	bdata->hdr.msg.len = len;
@@ -813,8 +796,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+}
 
-	return;
+/*
+ * Send a watch event.
+ * As this is not directly related to the current command, errors can't be
+ * reported.
+ */
+void send_event(struct connection *conn, const char *path, const char *token)
+{
+	struct buffered_data *bdata;
+	unsigned int len;
+
+	len = strlen(path) + 1 + strlen(token) + 1;
+	/* Don't try to send over-long events. */
+	if (len > XENSTORE_PAYLOAD_MAX)
+		return;
+
+	bdata = new_buffer(conn);
+	if (!bdata)
+		return;
+
+	bdata->buffer = talloc_array(bdata, char, len);
+	if (!bdata->buffer) {
+		talloc_free(bdata);
+		return;
+	}
+	strcpy(bdata->buffer, path);
+	strcpy(bdata->buffer + strlen(path) + 1, token);
+	bdata->hdr.msg.type = XS_WATCH_EVENT;
+	bdata->hdr.msg.len = len;
+
+	/* Queue for later transmission. */
+	list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 7d0fe77e79..99a0373944 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -187,6 +187,7 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
+void send_event(struct connection *conn, const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index aca0a71bad..99a2c266b2 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -85,35 +85,6 @@ static const char *get_watch_path(const struct watch *watch, const char *name)
 	return path;
 }
 
-/*
- * Send a watch event.
- * Temporary memory allocations are done with ctx.
- */
-static void add_event(struct connection *conn,
-		      const void *ctx,
-		      struct watch *watch,
-		      const char *name)
-{
-	/* Data to send (node\0token\0). */
-	unsigned int len;
-	char *data;
-
-	name = get_watch_path(watch, name);
-
-	len = strlen(name) + 1 + strlen(watch->token) + 1;
-	/* Don't try to send over-long events. */
-	if (len > XENSTORE_PAYLOAD_MAX)
-		return;
-
-	data = talloc_array(ctx, char, len);
-	if (!data)
-		return;
-	strcpy(data, name);
-	strcpy(data + strlen(name) + 1, watch->token);
-	send_reply(conn, XS_WATCH_EVENT, data, len);
-	talloc_free(data);
-}
-
 /*
  * Check permissions of a specific watch to fire:
  * Either the node itself or its parent have to be readable by the connection
@@ -190,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					add_event(i, ctx, watch, name);
+					send_event(i,
+						   get_watch_path(watch, name),
+						   watch->token);
 			}
 		}
 	}
@@ -292,7 +267,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	send_ack(conn, XS_WATCH);
 
 	/* We fire once up front: simplifies clients and restart. */
-	add_event(conn, in, watch, watch->node);
+	send_event(conn, get_watch_path(watch, watch->node), watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:11:43 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:11:43 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435876.689703 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCat-0004lP-Lo; Wed, 02 Nov 2022 12:11:43 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435876.689703; Wed, 02 Nov 2022 12:11:43 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCat-0004lH-It; Wed, 02 Nov 2022 12:11:43 +0000
Received: by outflank-mailman (input) for mailman id 435876;
 Wed, 02 Nov 2022 12:11:42 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCas-0004l0-Fb
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCas-0000qH-Eu
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCas-0001Hv-E7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=RKTa0+BrU3KSRSAVmvcCFuI2Ph1yR7l+yiX/bh8RO1M=; b=bjwBPw2Ul/y4Scq+MGFrz9dlPS
	ck8J2mruyQhfNmdInGHPAZO+Z51TfJLJysFpuazsZLErvTEPMfMncR3Hxp2UJ/j3GJT3X2agZgQlo
	ws/moVeAMTvIg30GZcQHAv89ad+KmvQrAum7jwNk1Q7gLDnlxu4oAYsmcBLYWcBGq/rA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: add helpers to free struct buffered_data
Message-Id: <E1oqCas-0001Hv-E7@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:11:42 +0000

commit ead062a68a9c201a95488e84750a70a107f7b317
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add helpers to free struct buffered_data
    
    Add two helpers for freeing struct buffered_data: free_buffered_data()
    for freeing one instance and conn_free_buffered_data() for freeing all
    instances for a connection.
    
    This is avoiding duplicated code and will help later when more actions
    are needed when freeing a struct buffered_data.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 18 ++++++++++++++++--
 tools/xenstore/xenstored_core.h   |  2 ++
 tools/xenstore/xenstored_domain.c | 15 ++-------------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index ed742d9dfc..61fc368e8c 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -207,6 +207,21 @@ void reopen_log(void)
 	}
 }
 
+static void free_buffered_data(struct buffered_data *out,
+			       struct connection *conn)
+{
+	list_del(&out->list);
+	talloc_free(out);
+}
+
+void conn_free_buffered_data(struct connection *conn)
+{
+	struct buffered_data *out;
+
+	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
+		free_buffered_data(out, conn);
+}
+
 static bool write_messages(struct connection *conn)
 {
 	int ret;
@@ -250,8 +265,7 @@ static bool write_messages(struct connection *conn)
 
 	trace_io(conn, out, 1);
 
-	list_del(&out->list);
-	talloc_free(out);
+	free_buffered_data(out, conn);
 
 	return true;
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 99a0373944..c9ea796185 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -271,6 +271,8 @@ int remember_string(struct hashtable *hash, const char *str);
 
 void set_tdb_key(const char *name, TDB_DATA *key);
 
+void conn_free_buffered_data(struct connection *conn);
+
 const char *dump_state_global(FILE *fp);
 const char *dump_state_buffered_data(FILE *fp, const struct connection *c,
 				     struct xs_state_connection *sc);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index ead4c237d2..de349e2a77 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -411,15 +411,10 @@ static struct domain *find_domain_by_domid(unsigned int domid)
 static void domain_conn_reset(struct domain *domain)
 {
 	struct connection *conn = domain->conn;
-	struct buffered_data *out;
 
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	while ((out = list_top(&conn->out_list, struct buffered_data, list))) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 
@@ -436,8 +431,6 @@ static void domain_conn_reset(struct domain *domain)
  */
 void ignore_connection(struct connection *conn, unsigned int err)
 {
-	struct buffered_data *out, *tmp;
-
 	trace("CONN %p ignored, reason %u\n", conn, err);
 
 	if (conn->domain && conn->domain->interface)
@@ -446,11 +439,7 @@ void ignore_connection(struct connection *conn, unsigned int err)
 	conn->is_ignored = true;
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
-
-	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
-		list_del(&out->list);
-		talloc_free(out);
-	}
+	conn_free_buffered_data(conn);
 
 	talloc_free(conn->in);
 	conn->in = NULL;
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:11:53 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:11:53 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435877.689707 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCb3-0004nn-ND; Wed, 02 Nov 2022 12:11:53 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435877.689707; Wed, 02 Nov 2022 12:11:53 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCb3-0004nf-KN; Wed, 02 Nov 2022 12:11:53 +0000
Received: by outflank-mailman (input) for mailman id 435877;
 Wed, 02 Nov 2022 12:11:52 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCb2-0004nX-JL
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:52 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCb2-0000rX-IF
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:52 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCb2-0001IT-HE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:11:52 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9xW2nZrsWbdQj6SGmUIjrGEUm1qSXLGEFM7Wgb+r93k=; b=fIXpojWDFrr4+Q0IoM4e2pcNyV
	GsUyiCIiDfbbddfoOKnuo7KbRLZI1h3trVlMiihP7vzWcRenTZVZEZnO3ufckSwaWE5XjKwFWxBI7
	bqm00CCyxHtbKkeQhg99sEH79ow283D8Ds1berxT49KPzGxnqTgUcOX9St42pikypfD4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: reduce number of watch events
Message-Id: <E1oqCb2-0001IT-HE@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:11:52 +0000

commit 3a96013a3e17baa07410b1b9776225d1d9a74297
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: reduce number of watch events
    
    When removing a watched node outside of a transaction, two watch events
    are being produced instead of just a single one.
    
    When finalizing a transaction watch events can be generated for each
    node which is being modified, even if outside a transaction such
    modifications might not have resulted in a watch event.
    
    This happens e.g.:
    
    - for nodes which are only modified due to added/removed child entries
    - for nodes being removed or created implicitly (e.g. creation of a/b/c
      is implicitly creating a/b, resulting in watch events for a, a/b and
      a/b/c instead of a/b/c only)
    
    Avoid these additional watch events, in order to reduce the needed
    memory inside Xenstore for queueing them.
    
    This is being achieved by adding event flags to struct accessed_node
    specifying whether an event should be triggered, and whether it should
    be an exact match of the modified path. Both flags can be set from
    fire_watches() instead of implying them only.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c        | 19 ++++++++--------
 tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------
 tools/xenstore/xenstored_transaction.h |  3 +++
 tools/xenstore/xenstored_watch.c       |  7 ++++--
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 61fc368e8c..b9a0ff5e05 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1291,7 +1291,7 @@ static void delete_child(struct connection *conn,
 }
 
 static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node)
+		       struct node *parent, struct node *node, bool watch_exact)
 {
 	char *name;
 
@@ -1303,7 +1303,7 @@ static int delete_node(struct connection *conn, const void *ctx,
 				       node->children);
 		child = name ? read_node(conn, node, name) : NULL;
 		if (child) {
-			if (delete_node(conn, ctx, node, child))
+			if (delete_node(conn, ctx, node, child, true))
 				return errno;
 		} else {
 			trace("delete_node: Error deleting child '%s/%s'!\n",
@@ -1315,7 +1315,12 @@ static int delete_node(struct connection *conn, const void *ctx,
 		talloc_free(name);
 	}
 
-	fire_watches(conn, ctx, node->name, node, true, NULL);
+	/*
+	 * Fire the watches now, when we can still see the node permissions.
+	 * This fine as we are single threaded and the next possible read will
+	 * be handled only after the node has been really removed.
+	 */
+	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
 	delete_node_single(conn, node);
 	delete_child(conn, parent, basename(node->name));
 	talloc_free(node);
@@ -1341,13 +1346,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 		return (errno == ENOMEM) ? ENOMEM : EINVAL;
 	node->parent = parent;
 
-	/*
-	 * Fire the watches now, when we can still see the node permissions.
-	 * This fine as we are single threaded and the next possible read will
-	 * be handled only after the node has been really removed.
-	 */
-	fire_watches(conn, ctx, name, node, false, NULL);
-	return delete_node(conn, ctx, parent, node);
+	return delete_node(conn, ctx, parent, node, false);
 }
 
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index faf6c930e4..54432907fc 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -130,6 +130,10 @@ struct accessed_node
 
 	/* Transaction node in data base? */
 	bool ta_node;
+
+	/* Watch event flags. */
+	bool fire_watch;
+	bool watch_exact;
 };
 
 struct changed_domain
@@ -323,6 +327,29 @@ err:
 	return ret;
 }
 
+/*
+ * A watch event should be fired for a node modified inside a transaction.
+ * Set the corresponding information. A non-exact event is replacing an exact
+ * one, but not the other way round.
+ */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact)
+{
+	struct accessed_node *i;
+
+	i = find_accessed_node(conn->transaction, name);
+	if (!i) {
+		conn->transaction->fail = true;
+		return;
+	}
+
+	if (!i->fire_watch) {
+		i->fire_watch = true;
+		i->watch_exact = watch_exact;
+	} else if (!watch_exact) {
+		i->watch_exact = false;
+	}
+}
+
 /*
  * Finalize transaction:
  * Walk through accessed nodes and check generation against global data.
@@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn,
 				ret = tdb_store(tdb_ctx, key, data,
 						TDB_REPLACE);
 				talloc_free(data.dptr);
-				if (ret)
-					goto err;
-				fire_watches(conn, trans, i->node, NULL, false,
-					     i->perms.p ? &i->perms : NULL);
 			} else {
-				fire_watches(conn, trans, i->node, NULL, false,
+				ret = tdb_delete(tdb_ctx, key);
+			}
+			if (ret)
+				goto err;
+			if (i->fire_watch) {
+				fire_watches(conn, trans, i->node, NULL,
+					     i->watch_exact,
 					     i->perms.p ? &i->perms : NULL);
-				if (tdb_delete(tdb_ctx, key))
-					goto err;
 			}
 		}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 14062730e3..0093cac807 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 int access_node(struct connection *conn, struct node *node,
                 enum node_access_type type, TDB_DATA *key);
 
+/* Queue watches for a modified node. */
+void queue_watches(struct connection *conn, const char *name, bool watch_exact);
+
 /* Prepend the transaction to name if appropriate. */
 int transaction_prepend(struct connection *conn, const char *name,
                         TDB_DATA *key);
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 99a2c266b2..205d9d8ea1 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -29,6 +29,7 @@
 #include "xenstore_lib.h"
 #include "utils.h"
 #include "xenstored_domain.h"
+#include "xenstored_transaction.h"
 
 extern int quota_nb_watch_per_domain;
 
@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 	struct connection *i;
 	struct watch *watch;
 
-	/* During transactions, don't fire watches. */
-	if (conn && conn->transaction)
+	/* During transactions, don't fire watches, but queue them. */
+	if (conn && conn->transaction) {
+		queue_watches(conn, name, exact);
 		return;
+	}
 
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:12:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:12:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435878.689710 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbE-0004qu-PA; Wed, 02 Nov 2022 12:12:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435878.689710; Wed, 02 Nov 2022 12:12:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbE-0004qn-M4; Wed, 02 Nov 2022 12:12:04 +0000
Received: by outflank-mailman (input) for mailman id 435878;
 Wed, 02 Nov 2022 12:12:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbC-0004qG-M7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbC-0000s0-LT
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbC-0001JE-Kj
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ptTaWbF6LzjLS71Wi5HCKZBLiFZvVil4xvYK5jsHJ78=; b=SpmQ8GzVTSUUigvLYJFf3TIWey
	kbXDr1sJS96nzeA7M0FYvhRFDfAr4PvFQYAmeufa1oueVNVDtJCLk4RdHRn2ws2hpzfEH9m1CFIP9
	9KGc4u46GJC41NijdsQ+kezhmaC3v+uIFuMDNFtcDhShaKVxUtZw+mLJOW7iTiLhkftA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: let unread watch events time out
Message-Id: <E1oqCbC-0001JE-Kj@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:12:02 +0000

commit 5285dcb1a5c01695c11e6397c95d906b5e765c98
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:07 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: let unread watch events time out
    
    A future modification will limit the number of outstanding requests
    for a domain, where "outstanding" means that the response of the
    request or any resulting watch event hasn't been consumed yet.
    
    In order to avoid a malicious guest being capable to block other guests
    by not reading watch events, add a timeout for watch events. In case a
    watch event hasn't been consumed after this timeout, it is being
    deleted. Set the default timeout to 20 seconds (a random value being
    not too high).
    
    In order to support to specify other timeout values in future, use a
    generic command line option for that purpose:
    
    --timeout|-w watch-event=<seconds>
    
    This is part of XSA-326 / CVE-2022-42311.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 133 +++++++++++++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h |   6 ++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b9a0ff5e05..cce02f24b5 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -108,6 +108,8 @@ int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 
+unsigned int timeout_watch_event_msec = 20000;
+
 void trace(const char *fmt, ...)
 {
 	va_list arglist;
@@ -207,19 +209,92 @@ void reopen_log(void)
 	}
 }
 
+static uint64_t get_now_msec(void)
+{
+	struct timespec now_ts;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &now_ts))
+		barf_perror("Could not find time (clock_gettime failed)");
+
+	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
+}
+
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
+	struct buffered_data *req;
+
 	list_del(&out->list);
+
+	/*
+	 * Update conn->timeout_msec with the next found timeout value in the
+	 * queued pending requests.
+	 */
+	if (out->timeout_msec) {
+		conn->timeout_msec = 0;
+		list_for_each_entry(req, &conn->out_list, list) {
+			if (req->timeout_msec) {
+				conn->timeout_msec = req->timeout_msec;
+				break;
+			}
+		}
+	}
+
 	talloc_free(out);
 }
 
+static void check_event_timeout(struct connection *conn, uint64_t msecs,
+				int *ptimeout)
+{
+	uint64_t delta;
+	struct buffered_data *out, *tmp;
+
+	if (!conn->timeout_msec)
+		return;
+
+	delta = conn->timeout_msec - msecs;
+	if (conn->timeout_msec <= msecs) {
+		delta = 0;
+		list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
+			/*
+			 * Only look at buffers with timeout and no data
+			 * already written to the ring.
+			 */
+			if (out->timeout_msec && out->inhdr && !out->used) {
+				if (out->timeout_msec > msecs) {
+					conn->timeout_msec = out->timeout_msec;
+					delta = conn->timeout_msec - msecs;
+					break;
+				}
+
+				/*
+				 * Free out without updating conn->timeout_msec,
+				 * as the update is done in this loop already.
+				 */
+				out->timeout_msec = 0;
+				trace("watch event path %s for domain %u timed out\n",
+				      out->buffer, conn->id);
+				free_buffered_data(out, conn);
+			}
+		}
+		if (!delta) {
+			conn->timeout_msec = 0;
+			return;
+		}
+	}
+
+	if (*ptimeout == -1 || *ptimeout > delta)
+		*ptimeout = delta;
+}
+
 void conn_free_buffered_data(struct connection *conn)
 {
 	struct buffered_data *out;
 
 	while ((out = list_top(&conn->out_list, struct buffered_data, list)))
 		free_buffered_data(out, conn);
+
+	conn->timeout_msec = 0;
 }
 
 static bool write_messages(struct connection *conn)
@@ -407,6 +482,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 {
 	struct connection *conn;
 	struct wrl_timestampt now;
+	uint64_t msecs;
 
 	if (fds)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
@@ -427,10 +503,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout)
 
 	wrl_gettime_now(&now);
 	wrl_log_periodic(now);
+	msecs = get_now_msec();
 
 	list_for_each_entry(conn, &connections, list) {
 		if (conn->domain) {
 			wrl_check_timeout(conn->domain, now, ptimeout);
+			check_event_timeout(conn, msecs, ptimeout);
 			if (conn_can_read(conn) ||
 			    (conn_can_write(conn) &&
 			     !list_empty(&conn->out_list)))
@@ -790,6 +868,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		return;
 	bdata->inhdr = true;
 	bdata->used = 0;
+	bdata->timeout_msec = 0;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -841,6 +920,12 @@ void send_event(struct connection *conn, const char *path, const char *token)
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
 }
@@ -2185,6 +2270,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
+"                          allowed timeout candidates are:\n"
+"                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
@@ -2207,6 +2295,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
 	{ "verbose", 0, NULL, 'V' },
@@ -2220,6 +2309,39 @@ int dom0_domid = 0;
 int dom0_event = 0;
 int priv_domid = 0;
 
+static int get_optval_int(const char *arg)
+{
+	char *end;
+	long val;
+
+	val = strtol(arg, &end, 10);
+	if (!*arg || *end || val < 0 || val > INT_MAX)
+		barf("invalid parameter value \"%s\"\n", arg);
+
+	return val;
+}
+
+static bool what_matches(const char *arg, const char *what)
+{
+	unsigned int what_len = strlen(what);
+
+	return !strncmp(arg, what, what_len) && arg[what_len] == '=';
+}
+
+static void set_timeout(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<seconds>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "watch-event"))
+		timeout_watch_event_msec = val * 1000;
+	else
+		barf("unknown timeout \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2234,7 +2356,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:U", options,
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2284,6 +2406,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'w':
+			set_timeout(optarg);
+			break;
 		case 'e':
 			dom0_event = strtol(optarg, NULL, 10);
 			break;
@@ -2714,6 +2839,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 		barf("error restoring buffered data");
 
 	memcpy(bdata->buffer, data, len);
+	if (bdata->hdr.msg.type == XS_WATCH_EVENT && timeout_watch_event_msec &&
+	    domain_is_unprivileged(conn)) {
+		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
+		if (!conn->timeout_msec)
+			conn->timeout_msec = bdata->timeout_msec;
+	}
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index c9ea796185..745262af96 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <time.h>
 #include <errno.h>
 
 #include "xenstore_lib.h"
@@ -67,6 +68,8 @@ struct buffered_data
 		char raw[sizeof(struct xsd_sockmsg)];
 	} hdr;
 
+	uint64_t timeout_msec;
+
 	/* The actual data. */
 	char *buffer;
 	char default_buffer[DEFAULT_BUFFER_SIZE];
@@ -118,6 +121,7 @@ struct connection
 
 	/* Buffered output data */
 	struct list_head out_list;
+	uint64_t timeout_msec;
 
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
@@ -242,6 +246,8 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 
+extern unsigned int timeout_watch_event_msec;
+
 /* Map the kernel's xenstore page. */
 void *xenbus_map(void);
 void unmap_xenbus(void *interface);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:12:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:12:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435879.689713 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbO-0004u2-Qu; Wed, 02 Nov 2022 12:12:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435879.689713; Wed, 02 Nov 2022 12:12:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbO-0004tv-O4; Wed, 02 Nov 2022 12:12:14 +0000
Received: by outflank-mailman (input) for mailman id 435879;
 Wed, 02 Nov 2022 12:12:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbM-0004tX-PU
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbM-0000s7-On
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbM-0001LT-Ns
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5SHP1XCoxseF/CanCM9XDRJU91PWeVJqM5yAeuoZgnc=; b=acVwb6R0rfld2pgCJK7ldAr0PU
	PdFoL+yY5YLRTmZnZhdDgmWkr9369J4mMPgLeDiolTXID105qzb61+qSke3UVNWKgnQfhO87Jxr0U
	G72hrmWJKEUT9c0ezNf16wNnMWk85HCo451i7DYYYscRkbCbtjBOgneXokeHJNFLpGZc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: limit outstanding requests
Message-Id: <E1oqCbM-0001LT-Ns@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:12:12 +0000

commit 36de433a273f55d614c83b89c9a8972287a1e475
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: limit outstanding requests
    
    Add another quota for limiting the number of outstanding requests of a
    guest. As the way to specify quotas on the command line is becoming
    rather nasty, switch to a new scheme using [--quota|-Q] <what>=<val>
    allowing to add more quotas in future easily.
    
    Set the default value to 20 (basically a random value not seeming to
    be too high or too low).
    
    A request is said to be outstanding if any message generated by this
    request (the direct response plus potential watch events) is not yet
    completely stored into a ring buffer. The initial watch event sent as
    a result of registering a watch is an exception.
    
    Note that across a live update the relation to buffered watch events
    for other domains is lost.
    
    Use talloc_zero() for allocating the domain structure in order to have
    all per-domain quota zeroed initially.
    
    This is part of XSA-326 / CVE-2022-42312.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 88 +++++++++++++++++++++++++++++++++++++--
 tools/xenstore/xenstored_core.h   | 20 ++++++++-
 tools/xenstore/xenstored_domain.c | 38 ++++++++++++++---
 tools/xenstore/xenstored_domain.h |  3 ++
 tools/xenstore/xenstored_watch.c  | 15 +++++--
 5 files changed, 150 insertions(+), 14 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index cce02f24b5..54e6add1a1 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -107,6 +107,7 @@ int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
+int quota_req_outstanding = 20;
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -219,12 +220,24 @@ static uint64_t get_now_msec(void)
 	return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
 }
 
+/*
+ * Remove a struct buffered_data from the list of outgoing data.
+ * A struct buffered_data related to a request having caused watch events to be
+ * sent is kept until all those events have been written out.
+ * Each watch event is referencing the related request via pend.req, while the
+ * number of watch events caused by a request is kept in pend.ref.event_cnt
+ * (those two cases are mutually exclusive, so the two fields can share memory
+ * via a union).
+ * The struct buffered_data is freed only if no related watch event is
+ * referencing it. The related return data can be freed right away.
+ */
 static void free_buffered_data(struct buffered_data *out,
 			       struct connection *conn)
 {
 	struct buffered_data *req;
 
 	list_del(&out->list);
+	out->on_out_list = false;
 
 	/*
 	 * Update conn->timeout_msec with the next found timeout value in the
@@ -240,6 +253,30 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	if (out->hdr.msg.type == XS_WATCH_EVENT) {
+		req = out->pend.req;
+		if (req) {
+			req->pend.ref.event_cnt--;
+			if (!req->pend.ref.event_cnt && !req->on_out_list) {
+				if (req->on_ref_list) {
+					domain_outstanding_domid_dec(
+						req->pend.ref.domid);
+					list_del(&req->list);
+				}
+				talloc_free(req);
+			}
+		}
+	} else if (out->pend.ref.event_cnt) {
+		/* Hang out off from conn. */
+		talloc_steal(NULL, out);
+		if (out->buffer != out->default_buffer)
+			talloc_free(out->buffer);
+		list_add(&out->list, &conn->ref_list);
+		out->on_ref_list = true;
+		return;
+	} else
+		domain_outstanding_dec(conn);
+
 	talloc_free(out);
 }
 
@@ -401,6 +438,7 @@ int delay_request(struct connection *conn, struct buffered_data *in,
 static int destroy_conn(void *_conn)
 {
 	struct connection *conn = _conn;
+	struct buffered_data *req;
 
 	/* Flush outgoing if possible, but don't block. */
 	if (!conn->domain) {
@@ -414,6 +452,11 @@ static int destroy_conn(void *_conn)
 				break;
 		close(conn->fd);
 	}
+
+	conn_free_buffered_data(conn);
+	list_for_each_entry(req, &conn->ref_list, list)
+		req->on_ref_list = false;
+
         if (conn->target)
                 talloc_unlink(conn, conn->target);
 	list_del(&conn->list);
@@ -889,6 +932,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	domain_outstanding_inc(conn);
 }
 
 /*
@@ -896,7 +941,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
  * As this is not directly related to the current command, errors can't be
  * reported.
  */
-void send_event(struct connection *conn, const char *path, const char *token)
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token)
 {
 	struct buffered_data *bdata;
 	unsigned int len;
@@ -926,8 +972,13 @@ void send_event(struct connection *conn, const char *path, const char *token)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->pend.req = req;
+	if (req)
+		req->pend.ref.event_cnt++;
+
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1714,6 +1765,7 @@ static void handle_input(struct connection *conn)
 			return;
 	}
 	in = conn->in;
+	in->pend.ref.domid = conn->id;
 
 	/* Not finished header yet? */
 	if (in->inhdr) {
@@ -1787,6 +1839,7 @@ struct connection *new_connection(const struct interface_funcs *funcs)
 	new->is_stalled = false;
 	new->transaction_started = 0;
 	INIT_LIST_HEAD(&new->out_list);
+	INIT_LIST_HEAD(&new->ref_list);
 	INIT_LIST_HEAD(&new->watches);
 	INIT_LIST_HEAD(&new->transaction_list);
 	INIT_LIST_HEAD(&new->delayed);
@@ -2270,6 +2323,9 @@ static void usage(void)
 "  -t, --transaction <nb>  limit the number of transaction allowed per domain,\n"
 "  -A, --perm-nb <nb>      limit the number of permissions per node,\n"
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
+"  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
+"                          quotas are:\n"
+"                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2295,6 +2351,7 @@ static struct option options[] = {
 	{ "transaction", 1, NULL, 't' },
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
+	{ "quota", 1, NULL, 'Q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2342,6 +2399,20 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
+static void set_quota(const char *arg)
+{
+	const char *eq = strchr(arg, '=');
+	int val;
+
+	if (!eq)
+		barf("quotas must be specified via <what>=<nb>\n");
+	val = get_optval_int(eq + 1);
+	if (what_matches(arg, "outstanding"))
+		quota_req_outstanding = val;
+	else
+		barf("unknown quota \"%s\"\n", arg);
+}
+
 int main(int argc, char *argv[])
 {
 	int opt;
@@ -2356,8 +2427,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options,
-				  NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
 			no_domain_init = true;
@@ -2406,6 +2477,9 @@ int main(int argc, char *argv[])
 			quota_max_path_len = min(XENSTORE_REL_PATH_MAX,
 						 quota_max_path_len);
 			break;
+		case 'Q':
+			set_quota(optarg);
+			break;
 		case 'w':
 			set_timeout(optarg);
 			break;
@@ -2848,6 +2922,14 @@ static void add_buffered_data(struct buffered_data *bdata,
 
 	/* Queue for later transmission. */
 	list_add_tail(&bdata->list, &conn->out_list);
+	bdata->on_out_list = true;
+	/*
+	 * Watch events are never "outstanding", but the request causing them
+	 * are instead kept "outstanding" until all watch events caused by that
+	 * request have been delivered.
+	 */
+	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
+		domain_outstanding_inc(conn);
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 745262af96..acb6b9fe2a 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -56,6 +56,8 @@ struct xs_state_connection;
 struct buffered_data
 {
 	struct list_head list;
+	bool on_out_list;
+	bool on_ref_list;
 
 	/* Are we still doing the header? */
 	bool inhdr;
@@ -63,6 +65,17 @@ struct buffered_data
 	/* How far are we? */
 	unsigned int used;
 
+	/* Outstanding request accounting. */
+	union {
+		/* ref is being used for requests. */
+		struct {
+			unsigned int event_cnt; /* # of outstanding events. */
+			unsigned int domid;     /* domid of request. */
+		} ref;
+		/* req is being used for watch events. */
+		struct buffered_data *req;      /* request causing event. */
+	} pend;
+
 	union {
 		struct xsd_sockmsg msg;
 		char raw[sizeof(struct xsd_sockmsg)];
@@ -123,6 +136,9 @@ struct connection
 	struct list_head out_list;
 	uint64_t timeout_msec;
 
+	/* Referenced requests no longer pending. */
+	struct list_head ref_list;
+
 	/* Transaction context for current request (NULL if none). */
 	struct transaction *transaction;
 
@@ -191,7 +207,8 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset);
 
 void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 		const void *data, unsigned int len);
-void send_event(struct connection *conn, const char *path, const char *token);
+void send_event(struct buffered_data *req, struct connection *conn,
+		const char *path, const char *token);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
 void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
@@ -245,6 +262,7 @@ extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
+extern int quota_req_outstanding;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index de349e2a77..c0a37712f8 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -78,6 +78,9 @@ struct domain
 	/* number of watch for this domain */
 	int nbwatch;
 
+	/* Number of outstanding requests. */
+	int nboutstanding;
+
 	/* write rate limit */
 	wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */
 	struct wrl_timestampt wrl_timestamp;
@@ -183,8 +186,12 @@ static bool domain_can_read(struct connection *conn)
 {
 	struct xenstore_domain_interface *intf = conn->domain->interface;
 
-	if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0)
-		return false;
+	if (domain_is_unprivileged(conn)) {
+		if (conn->domain->wrl_credit < 0)
+			return false;
+		if (conn->domain->nboutstanding >= quota_req_outstanding)
+			return false;
+	}
 
 	return (intf->req_cons != intf->req_prod);
 }
@@ -331,7 +338,7 @@ static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
 
-	domain = talloc(context, struct domain);
+	domain = talloc_zero(context, struct domain);
 	if (!domain) {
 		errno = ENOMEM;
 		return NULL;
@@ -392,9 +399,6 @@ static int new_domain(struct domain *domain, int port, bool restore)
 	domain->conn->domain = domain;
 	domain->conn->id = domain->domid;
 
-	domain->nbentry = 0;
-	domain->nbwatch = 0;
-
 	return 0;
 }
 
@@ -970,6 +974,28 @@ int domain_watch(struct connection *conn)
 		: 0;
 }
 
+void domain_outstanding_inc(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding++;
+}
+
+void domain_outstanding_dec(struct connection *conn)
+{
+	if (!conn || !conn->domain)
+		return;
+	conn->domain->nboutstanding--;
+}
+
+void domain_outstanding_domid_dec(unsigned int domid)
+{
+	struct domain *d = find_domain_by_domid(domid);
+
+	if (d)
+		d->nboutstanding--;
+}
+
 static wrl_creditt wrl_config_writecost      = WRL_FACTOR;
 static wrl_creditt wrl_config_rate           = WRL_RATE   * WRL_FACTOR;
 static wrl_creditt wrl_config_dburst         = WRL_DBURST * WRL_FACTOR;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 4a37de67a0..617d0acfd7 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -65,6 +65,9 @@ int domain_entry(struct connection *conn);
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
+void domain_outstanding_inc(struct connection *conn);
+void domain_outstanding_dec(struct connection *conn);
+void domain_outstanding_domid_dec(unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 205d9d8ea1..0755ffa375 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		  struct node *node, bool exact, struct node_perms *perms)
 {
 	struct connection *i;
+	struct buffered_data *req;
 	struct watch *watch;
 
 	/* During transactions, don't fire watches, but queue them. */
@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		return;
 	}
 
+	req = domain_is_unprivileged(conn) ? conn->in : NULL;
+
 	/* Create an event for each watch. */
 	list_for_each_entry(i, &connections, list) {
 		/* introduce/release domain watches */
@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
 		list_for_each_entry(watch, &i->watches, list) {
 			if (exact) {
 				if (streq(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			} else {
 				if (is_child(name, watch->node))
-					send_event(i,
+					send_event(req, i,
 						   get_watch_path(watch, name),
 						   watch->token);
 			}
@@ -269,8 +272,12 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	trace_create(watch, "watch");
 	send_ack(conn, XS_WATCH);
 
-	/* We fire once up front: simplifies clients and restart. */
-	send_event(conn, get_watch_path(watch, watch->node), watch->token);
+	/*
+	 * We fire once up front: simplifies clients and restart.
+	 * This event will not be linked to the XS_WATCH request.
+	 */
+	send_event(NULL, conn, get_watch_path(watch, watch->node),
+		   watch->token);
 
 	return 0;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:12:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:12:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435880.689718 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbY-0004x6-Uw; Wed, 02 Nov 2022 12:12:24 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435880.689718; Wed, 02 Nov 2022 12:12:24 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbY-0004ww-S9; Wed, 02 Nov 2022 12:12:24 +0000
Received: by outflank-mailman (input) for mailman id 435880;
 Wed, 02 Nov 2022 12:12:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbW-0004wf-Sp
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbW-0000sH-S7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbW-0001Lw-RC
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=+VqNKd9XvXGfJ8uOMaA05to98BS9v5K0D4AgxDyJVOc=; b=c9Gr+4dmzP8kr2PMJ6Zsu4NM0V
	T+PHOD2MJvpSA/PvgFJRAv4QEzIuHryq/ZZaqrXbpQr0nRAB4T5RUUequlunXMh2urzFBsXpO9am3
	5fOHIiT6unesyoQNhJwxe9NYRWdB9Rt3AN6B2EPAJDLfyR42+E0Yn0ycN7v1JUmwq52U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: don't buffer multiple identical watch events
Message-Id: <E1oqCbW-0001Lw-RC@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:12:22 +0000

commit b5c0bdb96d33e18c324c13d8e33c08732d77eaa2
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: don't buffer multiple identical watch events
    
    A guest not reading its Xenstore response buffer fast enough might
    pile up lots of Xenstore watch events buffered. Reduce the generated
    load by dropping new events which already have an identical copy
    pending.
    
    The special events "@..." are excluded from that handling as there are
    known use cases where the handler is relying on each event to be sent
    individually.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 20 +++++++++++++++++++-
 tools/xenstore/xenstored_core.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 54e6add1a1..45feae313a 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -912,6 +912,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->inhdr = true;
 	bdata->used = 0;
 	bdata->timeout_msec = 0;
+	bdata->watch_event = false;
 
 	if (len <= DEFAULT_BUFFER_SIZE)
 		bdata->buffer = bdata->default_buffer;
@@ -944,7 +945,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 void send_event(struct buffered_data *req, struct connection *conn,
 		const char *path, const char *token)
 {
-	struct buffered_data *bdata;
+	struct buffered_data *bdata, *bd;
 	unsigned int len;
 
 	len = strlen(path) + 1 + strlen(token) + 1;
@@ -966,12 +967,29 @@ void send_event(struct buffered_data *req, struct connection *conn,
 	bdata->hdr.msg.type = XS_WATCH_EVENT;
 	bdata->hdr.msg.len = len;
 
+	/*
+	 * Check whether an identical event is pending already.
+	 * Special events are excluded from that check.
+	 */
+	if (path[0] != '@') {
+		list_for_each_entry(bd, &conn->out_list, list) {
+			if (bd->watch_event && bd->hdr.msg.len == len &&
+			    !memcmp(bdata->buffer, bd->buffer, len)) {
+				trace("dropping duplicate watch %s %s for domain %u\n",
+				      path, token, conn->id);
+				talloc_free(bdata);
+				return;
+			}
+		}
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
 			conn->timeout_msec = bdata->timeout_msec;
 	}
 
+	bdata->watch_event = true;
 	bdata->pend.req = req;
 	if (req)
 		req->pend.ref.event_cnt++;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index acb6b9fe2a..e1d47f8844 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -62,6 +62,9 @@ struct buffered_data
 	/* Are we still doing the header? */
 	bool inhdr;
 
+	/* Is this a watch event? */
+	bool watch_event;
+
 	/* How far are we? */
 	unsigned int used;
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:12:34 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:12:34 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435881.689722 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbi-000503-0T; Wed, 02 Nov 2022 12:12:34 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435881.689722; Wed, 02 Nov 2022 12:12:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbh-0004zt-Td; Wed, 02 Nov 2022 12:12:33 +0000
Received: by outflank-mailman (input) for mailman id 435881;
 Wed, 02 Nov 2022 12:12:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbh-0004ze-0E
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbg-0000sL-V2
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbg-0001Md-UN
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=xnQc0uaU+MWj0pePvv/P2XLXMt6mGc0ase9hO8dhO7o=; b=3kY/Zr+cJ8/YAEEBWoWyn1bQrk
	l7PLDRQgL6jx3pnJUCzlg+B7gpFFdJdjOjx+B47omfxNXGuoJHKml3oAXxIbXNeEh21uFjy+WiqMa
	WZ26nRaxgs/P2+DmefxowmouXQapYKfZCQ19fBf6qL//t9k87yImpAxqQipoIVBHwLu4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: fix connection->id usage
Message-Id: <E1oqCbg-0001Md-UN@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:12:32 +0000

commit 3047df38e1991510bc295e3e1bb6b6b6c4a97831
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: fix connection->id usage
    
    Don't use conn->id for privilege checks, but domain_is_unprivileged().
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_control.c     | 2 +-
 tools/xenstore/xenstored_core.h        | 2 +-
 tools/xenstore/xenstored_transaction.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index f0e00db633..61bcbc069d 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -878,7 +878,7 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	unsigned int cmd, num, off;
 	char **vec = NULL;
 
-	if (conn->id != 0)
+	if (domain_is_unprivileged(conn))
 		return EACCES;
 
 	off = get_string(in, 0);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index e1d47f8844..aa0dedde64 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -123,7 +123,7 @@ struct connection
 	/* The index of pollfd in global pollfd array */
 	int pollfd_idx;
 
-	/* Who am I? 0 for socket connections. */
+	/* Who am I? Domid of connection. */
 	unsigned int id;
 
 	/* Is this connection ignored? */
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 54432907fc..ee1b09031a 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -477,7 +477,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	if (conn->transaction)
 		return EBUSY;
 
-	if (conn->id && conn->transaction_started > quota_max_transaction)
+	if (domain_is_unprivileged(conn) &&
+	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
 	/* Attach transaction to input for autofree until it's complete */
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:12:44 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:12:44 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435882.689726 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbs-00052x-1u; Wed, 02 Nov 2022 12:12:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435882.689726; Wed, 02 Nov 2022 12:12:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCbr-00052o-VH; Wed, 02 Nov 2022 12:12:43 +0000
Received: by outflank-mailman (input) for mailman id 435882;
 Wed, 02 Nov 2022 12:12:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbr-00052d-2f
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbr-0000sQ-24
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCbr-0001NC-1B
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=BLeWY9AdZVz7ISx7N7DdvCNsiHSbK+akzk9liVSBwhM=; b=GLB5D9HKoYFfn1ng2L9ufZ5JrE
	IYhD/gINeGzmOl03u9U8gSnEyeqOJm678v28MtEezEoaGVfrrqExuEBcNx7wUkGKP4f6ysDIgwWWR
	5hfspOp5iTeECEfRwne1CBQM1aj9k/0SVMPmxqPMUzkQXDY3IvjSbwfmXnJi9nm8jSI4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: simplify and fix per domain node accounting
Message-Id: <E1oqCbr-0001NC-1B@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:12:43 +0000

commit dbef1f7482894c572d90cd73d99ed689c891e863
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:08 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: simplify and fix per domain node accounting
    
    The accounting of nodes can be simplified now that each connection
    holds the associated domid.
    
    Fix the node accounting to cover nodes created for a domain before it
    has been introduced. This requires to react properly to an allocation
    failure inside domain_entry_inc() by returning an error code.
    
    Especially in error paths the node accounting has to be fixed in some
    cases.
    
    This is part of XSA-326 / CVE-2022-42313.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c        |  43 +++++++++++---
 tools/xenstore/xenstored_domain.c      | 105 +++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h      |   4 +-
 tools/xenstore/xenstored_transaction.c |   8 ++-
 4 files changed, 109 insertions(+), 51 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 45feae313a..0a684450bc 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -634,7 +634,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(node)) {
+	if (domain_adjust_node_perms(conn, node)) {
 		talloc_free(node);
 		return NULL;
 	}
@@ -656,7 +656,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(node))
+	if (domain_adjust_node_perms(conn, node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1268,13 +1268,17 @@ nomem:
 	return NULL;
 }
 
-static int destroy_node(struct connection *conn, struct node *node)
+static void destroy_node_rm(struct node *node)
 {
 	if (streq(node->name, "/"))
 		corrupt(NULL, "Destroying root node!");
 
 	tdb_delete(tdb_ctx, node->key);
+}
 
+static int destroy_node(struct connection *conn, struct node *node)
+{
+	destroy_node_rm(node);
 	domain_entry_dec(conn, node);
 
 	/*
@@ -1324,8 +1328,12 @@ static struct node *create_node(struct connection *conn, const void *ctx,
 			goto err;
 
 		/* Account for new node */
-		if (i->parent)
-			domain_entry_inc(conn, i);
+		if (i->parent) {
+			if (domain_entry_inc(conn, i)) {
+				destroy_node_rm(i);
+				return NULL;
+			}
+		}
 	}
 
 	return node;
@@ -1610,10 +1618,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	old_perms = node->perms;
 	domain_entry_dec(conn, node);
 	node->perms = perms;
-	domain_entry_inc(conn, node);
+	if (domain_entry_inc(conn, node)) {
+		node->perms = old_perms;
+		/*
+		 * This should never fail because we had a reference on the
+		 * domain before and Xenstored is single-threaded.
+		 */
+		domain_entry_inc(conn, node);
+		return ENOMEM;
+	}
+
+	if (write_node(conn, node, false)) {
+		int saved_errno = errno;
 
-	if (write_node(conn, node, false))
+		domain_entry_dec(conn, node);
+		node->perms = old_perms;
+		/* No failure possible as above. */
+		domain_entry_inc(conn, node);
+
+		errno = saved_errno;
 		return errno;
+	}
 
 	fire_watches(conn, in, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
@@ -3095,7 +3120,9 @@ void read_state_node(const void *ctx, const void *state)
 	set_tdb_key(name, &key);
 	if (write_node_raw(NULL, &key, node, true))
 		barf("write node error restoring node");
-	domain_entry_inc(&conn, node);
+
+	if (domain_entry_inc(&conn, node))
+		barf("node accounting error restoring node");
 
 	talloc_free(node);
 }
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index c0a37712f8..44ce267ec5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -16,6 +16,7 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -363,6 +364,18 @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid)
 	return domain ? : alloc_domain(ctx, domid);
 }
 
+static struct domain *find_or_alloc_existing_domain(unsigned int domid)
+{
+	struct domain *domain;
+	xc_dominfo_t dominfo;
+
+	domain = find_domain_struct(domid);
+	if (!domain && get_domain_info(domid, &dominfo))
+		domain = alloc_domain(NULL, domid);
+
+	return domain;
+}
+
 static int new_domain(struct domain *domain, int port, bool restore)
 {
 	int rc;
@@ -814,30 +827,28 @@ void domain_deinit(void)
 		xenevtchn_unbind(xce_handle, virq_port);
 }
 
-void domain_entry_inc(struct connection *conn, struct node *node)
+int domain_entry_inc(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
-		return;
+		return 0;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d)
-				d->nbentry++;
-		}
-	} else if (conn->domain) {
-		if (conn->transaction) {
-			transaction_entry_inc(conn->transaction,
-				conn->domain->domid);
- 		} else {
- 			conn->domain->nbentry++;
-		}
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_inc(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_or_alloc_existing_domain(domid);
+		if (d)
+			d->nbentry++;
+		else
+			return ENOMEM;
 	}
+
+	return 0;
 }
 
 /*
@@ -873,7 +884,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct node *node)
+int domain_adjust_node_perms(struct connection *conn, struct node *node)
 {
 	unsigned int i;
 	int ret;
@@ -883,8 +894,14 @@ int domain_adjust_node_perms(struct node *node)
 		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret)
+	if (!ret) {
+		/*
+		 * In theory we'd need to update the number of dom0 nodes here,
+		 * but we could be called for a read of the node. So better
+		 * avoid the risk to overflow the node count of dom0.
+		 */
 		node->perms.p[0].id = priv_domid;
+	}
 
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
@@ -903,25 +920,25 @@ int domain_adjust_node_perms(struct node *node)
 void domain_entry_dec(struct connection *conn, struct node *node)
 {
 	struct domain *d;
+	unsigned int domid;
 
 	if (!conn)
 		return;
 
-	if (node->perms.p && node->perms.p[0].id != conn->id) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				node->perms.p[0].id);
-		} else {
-			d = find_domain_by_domid(node->perms.p[0].id);
-			if (d && d->nbentry)
-				d->nbentry--;
-		}
-	} else if (conn->domain && conn->domain->nbentry) {
-		if (conn->transaction) {
-			transaction_entry_dec(conn->transaction,
-				conn->domain->domid);
+	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+
+	if (conn->transaction) {
+		transaction_entry_dec(conn->transaction, domid);
+	} else {
+		d = (domid == conn->id && conn->domain) ? conn->domain
+		    : find_domain_struct(domid);
+		if (d) {
+			d->nbentry--;
 		} else {
-			conn->domain->nbentry--;
+			errno = ENOENT;
+			corrupt(conn,
+				"Node \"%s\" owned by non-existing domain %u\n",
+				node->name, domid);
 		}
 	}
 }
@@ -931,13 +948,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
 	struct domain *d;
 	int cnt;
 
-	d = find_domain_by_domid(domid);
-	if (!d)
-		return 0;
+	if (update) {
+		d = find_domain_struct(domid);
+		assert(d);
+	} else {
+		/*
+		 * We are called first with update == false in order to catch
+		 * any error. So do a possible allocation and check for error
+		 * only in this case, as in the case of update == true nothing
+		 * can go wrong anymore as the allocation already happened.
+		 */
+		d = find_or_alloc_existing_domain(domid);
+		if (!d)
+			return -1;
+	}
 
 	cnt = d->nbentry + num;
-	if (cnt < 0)
-		cnt = 0;
+	assert(cnt >= 0);
 
 	if (update)
 		d->nbentry = cnt;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 617d0acfd7..5937931314 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -55,10 +55,10 @@ const char *get_implicit_path(const struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct node *node);
+int domain_adjust_node_perms(struct connection *conn, struct node *node);
 
 /* Quota manipulation */
-void domain_entry_inc(struct connection *conn, struct node *);
+int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ee1b09031a..86caf6c398 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -519,8 +519,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 
 	list_for_each_entry(d, &trans->changed_domains, list) {
 		cnt = domain_entry_fix(d->domid, d->nbentry, update);
-		if (!update && cnt >= quota_nb_entry_per_domain)
-			return ENOSPC;
+		if (!update) {
+			if (cnt >= quota_nb_entry_per_domain)
+				return ENOSPC;
+			if (cnt < 0)
+				return ENOMEM;
+		}
 	}
 
 	return 0;
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:12:54 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:12:54 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435883.689731 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCc2-00055b-4D; Wed, 02 Nov 2022 12:12:54 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435883.689731; Wed, 02 Nov 2022 12:12:54 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCc2-00055T-0d; Wed, 02 Nov 2022 12:12:54 +0000
Received: by outflank-mailman (input) for mailman id 435883;
 Wed, 02 Nov 2022 12:12:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCc1-00055A-5v
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCc1-0000sk-5I
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCc1-0001Nb-4Z
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:12:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sUCx8VMX8hTjjmPRixex9hcR3KV0BDjddN6J1lke2F4=; b=w0JtyW5cJuhpjlNEkIFU7tz4bo
	RkWbWASVAWqJ9jAquxN9wacmEh+JdJcXqmCXFOddcb+ioonrhKEU9lIsvX0IGSKM5sZs2w95au5yy
	tnsaiMoIypuFxGhOJRZ8F6dhnJ+rJA+Hvk3IIhB+CFcn0bqgXuNv6EZXe3qoVTF0yqCs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: limit max number of nodes accessed in a transaction
Message-Id: <E1oqCc1-0001Nb-4Z@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:12:53 +0000

commit 268369d8e322d227a74a899009c5748d7b0ea142
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: limit max number of nodes accessed in a transaction
    
    Today a guest is free to access as many nodes in a single transaction
    as it wants. This can lead to unbounded memory consumption in Xenstore
    as there is the need to keep track of all nodes having been accessed
    during a transaction.
    
    In oxenstored the number of requests in a transaction is being limited
    via a quota maxrequests (default is 1024). As multiple accesses of a
    node are not problematic in C Xenstore, limit the number of accessed
    nodes.
    
    In order to let read_node() detect a quota error in case too many nodes
    are being accessed, check the return value of access_node() and return
    NULL in case an error has been seen. Introduce __must_check and add it
    to the access_node() prototype.
    
    This is part of XSA-326 / CVE-2022-42314.
    
    Suggested-by: Julien Grall <julien@xen.org>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/include/xen-tools/libs.h         |  4 +++
 tools/xenstore/xenstored_core.c        | 50 ++++++++++++++++++++++++----------
 tools/xenstore/xenstored_core.h        |  1 +
 tools/xenstore/xenstored_transaction.c |  9 ++++++
 tools/xenstore/xenstored_transaction.h |  4 +--
 5 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h
index a16e0c3807..bafc90e2f6 100644
--- a/tools/include/xen-tools/libs.h
+++ b/tools/include/xen-tools/libs.h
@@ -63,4 +63,8 @@
 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
 #endif
 
+#ifndef __must_check
+#define __must_check __attribute__((__warn_unused_result__))
+#endif
+
 #endif	/* __XEN_TOOLS_LIBS__ */
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 0a684450bc..d4fd005f59 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -106,6 +106,7 @@ int quota_nb_watch_per_domain = 128;
 int quota_max_entry_size = 2048; /* 2K */
 int quota_max_transaction = 10;
 int quota_nb_perms_per_node = 5;
+int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
 
@@ -591,6 +592,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	TDB_DATA key, data;
 	struct xs_tdb_record_hdr *hdr;
 	struct node *node;
+	int err;
 
 	node = talloc(ctx, struct node);
 	if (!node) {
@@ -612,14 +614,13 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	if (data.dptr == NULL) {
 		if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) {
 			node->generation = NO_GENERATION;
-			access_node(conn, node, NODE_ACCESS_READ, NULL);
-			errno = ENOENT;
+			err = access_node(conn, node, NODE_ACCESS_READ, NULL);
+			errno = err ? : ENOENT;
 		} else {
 			log("TDB error on read: %s", tdb_errorstr(tdb_ctx));
 			errno = EIO;
 		}
-		talloc_free(node);
-		return NULL;
+		goto error;
 	}
 
 	node->parent = NULL;
@@ -634,19 +635,36 @@ struct node *read_node(struct connection *conn, const void *ctx,
 
 	/* Permissions are struct xs_permissions. */
 	node->perms.p = hdr->perms;
-	if (domain_adjust_node_perms(conn, node)) {
-		talloc_free(node);
-		return NULL;
-	}
+	if (domain_adjust_node_perms(conn, node))
+		goto error;
 
 	/* Data is binary blob (usually ascii, no nul). */
 	node->data = node->perms.p + hdr->num_perms;
 	/* Children is strings, nul separated. */
 	node->children = node->data + node->datalen;
 
-	access_node(conn, node, NODE_ACCESS_READ, NULL);
+	if (access_node(conn, node, NODE_ACCESS_READ, NULL))
+		goto error;
 
 	return node;
+
+ error:
+	err = errno;
+	talloc_free(node);
+	errno = err;
+	return NULL;
+}
+
+static bool read_node_can_propagate_errno(void)
+{
+	/*
+	 * 2 error cases for read_node() can always be propagated up:
+	 * ENOMEM, because this has nothing to do with the node being in the
+	 * data base or not, but is caused by a general lack of memory.
+	 * ENOSPC, because this is related to hitting quota limits which need
+	 * to be respected.
+	 */
+	return errno == ENOMEM || errno == ENOSPC;
 }
 
 int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
@@ -763,7 +781,7 @@ static int ask_parents(struct connection *conn, const void *ctx,
 		node = read_node(conn, ctx, name);
 		if (node)
 			break;
-		if (errno == ENOMEM)
+		if (read_node_can_propagate_errno())
 			return errno;
 	} while (!streq(name, "/"));
 
@@ -825,7 +843,7 @@ static struct node *get_node(struct connection *conn,
 		}
 	}
 	/* Clean up errno if they weren't supposed to know. */
-	if (!node && errno != ENOMEM)
+	if (!node && !read_node_can_propagate_errno())
 		errno = errno_from_parents(conn, ctx, name, errno, perm);
 	return node;
 }
@@ -1231,7 +1249,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx,
 
 	/* If parent doesn't exist, create it. */
 	parent = read_node(conn, parentname, parentname);
-	if (!parent)
+	if (!parent && errno == ENOENT)
 		parent = construct_node(conn, ctx, parentname);
 	if (!parent)
 		return NULL;
@@ -1505,7 +1523,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
-		return (errno == ENOMEM) ? ENOMEM : EINVAL;
+		return read_node_can_propagate_errno() ? errno : EINVAL;
 	node->parent = parent;
 
 	return delete_node(conn, ctx, parent, node, false);
@@ -1535,7 +1553,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 				return 0;
 			}
 			/* Restore errno, just in case. */
-			if (errno != ENOMEM)
+			if (!read_node_can_propagate_errno())
 				errno = ENOENT;
 		}
 		return errno;
@@ -2368,6 +2386,8 @@ static void usage(void)
 "  -M, --path-max <chars>  limit the allowed Xenstore node path length,\n"
 "  -Q, --quota <what>=<nb> set the quota <what> to the value <nb>, allowed\n"
 "                          quotas are:\n"
+"                          transaction-nodes: number of accessed node per\n"
+"                                             transaction\n"
 "                          outstanding: number of outstanding requests\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
@@ -2452,6 +2472,8 @@ static void set_quota(const char *arg)
 	val = get_optval_int(eq + 1);
 	if (what_matches(arg, "outstanding"))
 		quota_req_outstanding = val;
+	else if (what_matches(arg, "transaction-nodes"))
+		quota_trans_nodes = val;
 	else
 		barf("unknown quota \"%s\"\n", arg);
 }
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index aa0dedde64..9c572a3c6e 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -266,6 +266,7 @@ extern int dom0_event;
 extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
+extern int quota_trans_nodes;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 86caf6c398..7bd41eb475 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -156,6 +156,9 @@ struct transaction
 	/* Connection-local identifier for this transaction. */
 	uint32_t id;
 
+	/* Node counter. */
+	unsigned int nodes;
+
 	/* Generation when transaction started. */
 	uint64_t generation;
 
@@ -260,6 +263,11 @@ int access_node(struct connection *conn, struct node *node,
 
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
+		if (trans->nodes >= quota_trans_nodes &&
+		    domain_is_unprivileged(conn)) {
+			ret = ENOSPC;
+			goto err;
+		}
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
@@ -297,6 +305,7 @@ int access_node(struct connection *conn, struct node *node,
 				i->ta_node = true;
 			}
 		}
+		trans->nodes++;
 		list_add_tail(&i->list, &trans->accessed);
 	}
 
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 0093cac807..e3cbd6b230 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid);
 void transaction_entry_dec(struct transaction *trans, unsigned int domid);
 
 /* This node was accessed. */
-int access_node(struct connection *conn, struct node *node,
-                enum node_access_type type, TDB_DATA *key);
+int __must_check access_node(struct connection *conn, struct node *node,
+                             enum node_access_type type, TDB_DATA *key);
 
 /* Queue watches for a modified node. */
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:13:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:13:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435884.689734 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcC-00059E-6O; Wed, 02 Nov 2022 12:13:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435884.689734; Wed, 02 Nov 2022 12:13:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcC-000596-3Z; Wed, 02 Nov 2022 12:13:04 +0000
Received: by outflank-mailman (input) for mailman id 435884;
 Wed, 02 Nov 2022 12:13:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcB-00058o-9G
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcB-0000t3-8c
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcB-0001OD-7m
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8qbpSeXwD5C12TUUoMZNLeuGDiTZ4A0KGMewg8//uUo=; b=PT4uAba5+glM0SpYreJ39hXL80
	RRUpPjOXxtWgbRIED5uQTs1XmtPoxAFicvNFmepIziaoakxW885eo9pOr+kvUPcSRi5MadLNw7Fr7
	PfNeiYnR6GXnesQZYD39X65Cv7GaXN+GG1Kg/Zm2pc01UWSmb3+lPRe6NoIJjecseT48=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: move the call of setup_structure() to dom0 introduction
Message-Id: <E1oqCcB-0001OD-7m@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:13:03 +0000

commit 60e2f6020dea7f616857b8fc1141b1c085d88761
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: move the call of setup_structure() to dom0 introduction
    
    Setting up the basic structure when introducing dom0 has the advantage
    to be able to add proper node memory accounting for the added nodes
    later.
    
    This makes it possible to do proper node accounting, too.
    
    An additional requirement to make that work fine is to correct the
    owner of the created nodes to be dom0_domid instead of domid 0.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 9 ++++-----
 tools/xenstore/xenstored_core.h   | 1 +
 tools/xenstore/xenstored_domain.c | 3 +++
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index d4fd005f59..844ae396a0 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2018,7 +2018,8 @@ static int tdb_flags;
 static void manual_node(const char *name, const char *child)
 {
 	struct node *node;
-	struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE };
+	struct xs_permissions perms = { .id = dom0_domid,
+					.perms = XS_PERM_NONE };
 
 	node = talloc_zero(NULL, struct node);
 	if (!node)
@@ -2057,7 +2058,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...)
 	}
 }
 
-static void setup_structure(bool live_update)
+void setup_structure(bool live_update)
 {
 	char *tdbname;
 
@@ -2080,6 +2081,7 @@ static void setup_structure(bool live_update)
 		manual_node("/", "tool");
 		manual_node("/tool", "xenstored");
 		manual_node("/tool/xenstored", NULL);
+		domain_entry_fix(dom0_domid, 3, true);
 	}
 
 	check_store();
@@ -2598,9 +2600,6 @@ int main(int argc, char *argv[])
 
 	init_pipe(reopen_log_pipe);
 
-	/* Setup the database */
-	setup_structure(live_update);
-
 	/* Listen to hypervisor. */
 	if (!no_domain_init && !live_update) {
 		domain_init(-1);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 9c572a3c6e..a772f3b8ea 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -231,6 +231,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+void setup_structure(bool live_update);
 struct connection *new_connection(const struct interface_funcs *funcs);
 struct connection *get_connection_by_id(unsigned int conn_id);
 void check_store(void);
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 44ce267ec5..5c79eed3dc 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -496,6 +496,9 @@ static struct domain *introduce_domain(const void *ctx,
 		}
 		domain->interface = interface;
 
+		if (is_master_domain)
+			setup_structure(restore);
+
 		/* Now domain belongs to its connection. */
 		talloc_steal(domain->conn, domain);
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:13:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:13:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435885.689738 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcM-0005Ck-80; Wed, 02 Nov 2022 12:13:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435885.689738; Wed, 02 Nov 2022 12:13:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcM-0005Cc-55; Wed, 02 Nov 2022 12:13:14 +0000
Received: by outflank-mailman (input) for mailman id 435885;
 Wed, 02 Nov 2022 12:13:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcL-0005CQ-CO
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcL-0000t7-Bo
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcL-0001Ol-B4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=DjKAxtd5UnQBDLlbqrGH3NpgcohR/3g80CvMu7msr7M=; b=RDyCRutJ1y4a/QK7D3JWRiRS76
	McH+PKKzh/d1vOrIE4b/a67oW54CVKI6dXRaxgOG6W+KcgCOTXqlcM0+2xjrYyPE1bKTpALTmxY4+
	oebyhTOv6OP4SqeKJgpY/OKhMy/qHZ6sKA9q8QujStrtM2q6FUoy/WfiQTTJYrnLJtiQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: add infrastructure to keep track of per domain memory usage
Message-Id: <E1oqCcL-0001Ol-B4@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:13:13 +0000

commit 0d4a8ec7a93faedbe54fd197db146de628459e77
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add infrastructure to keep track of per domain memory usage
    
    The amount of memory a domain can consume in Xenstore is limited by
    various quota today, but even with sane quota a domain can still
    consume rather large memory quantities.
    
    Add the infrastructure for keeping track of the amount of memory a
    domain is consuming in Xenstore. Note that this is only the memory a
    domain has direct control over, so any internal administration data
    needed by Xenstore only is not being accounted for.
    
    There are two quotas defined: a soft quota which will result in a
    warning issued via syslog() when it is exceeded, and a hard quota
    resulting in a stop of accepting further requests or watch events as
    long as the hard quota would be violated by accepting those.
    
    Setting any of those quotas to 0 will disable it.
    
    As default values use 2MB per domain for the soft limit (this basically
    covers the allowed case to create 1000 nodes needing 2kB each), and
    2.5MB for the hard limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 30 ++++++++++---
 tools/xenstore/xenstored_core.h   |  2 +
 tools/xenstore/xenstored_domain.c | 93 +++++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.h | 20 +++++++++
 4 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 844ae396a0..f03ad93b43 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -109,6 +109,8 @@ int quota_nb_perms_per_node = 5;
 int quota_trans_nodes = 1024;
 int quota_max_path_len = XENSTORE_REL_PATH_MAX;
 int quota_req_outstanding = 20;
+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */
+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */
 
 unsigned int timeout_watch_event_msec = 20000;
 
@@ -2390,7 +2392,14 @@ static void usage(void)
 "                          quotas are:\n"
 "                          transaction-nodes: number of accessed node per\n"
 "                                             transaction\n"
+"                          memory: total used memory per domain for nodes,\n"
+"                                  transactions, watches and requests, above\n"
+"                                  which Xenstore will stop talking to domain\n"
 "                          outstanding: number of outstanding requests\n"
+"  -q, --quota-soft <what>=<nb> set a soft quota <what> to the value <nb>,\n"
+"                          causing a warning to be issued via syslog() if the\n"
+"                          limit is violated, allowed quotas are:\n"
+"                          memory: see above\n"
 "  -w, --timeout <what>=<seconds>   set the timeout in seconds for <what>,\n"
 "                          allowed timeout candidates are:\n"
 "                          watch-event: time a watch-event is kept pending\n"
@@ -2417,6 +2426,7 @@ static struct option options[] = {
 	{ "perm-nb", 1, NULL, 'A' },
 	{ "path-max", 1, NULL, 'M' },
 	{ "quota", 1, NULL, 'Q' },
+	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
@@ -2464,7 +2474,7 @@ static void set_timeout(const char *arg)
 		barf("unknown timeout \"%s\"\n", arg);
 }
 
-static void set_quota(const char *arg)
+static void set_quota(const char *arg, bool soft)
 {
 	const char *eq = strchr(arg, '=');
 	int val;
@@ -2472,11 +2482,16 @@ static void set_quota(const char *arg)
 	if (!eq)
 		barf("quotas must be specified via <what>=<nb>\n");
 	val = get_optval_int(eq + 1);
-	if (what_matches(arg, "outstanding"))
+	if (what_matches(arg, "outstanding") && !soft)
 		quota_req_outstanding = val;
-	else if (what_matches(arg, "transaction-nodes"))
+	else if (what_matches(arg, "transaction-nodes") && !soft)
 		quota_trans_nodes = val;
-	else
+	else if (what_matches(arg, "memory")) {
+		if (soft)
+			quota_memory_per_domain_soft = val;
+		else
+			quota_memory_per_domain_hard = val;
+	} else
 		barf("unknown quota \"%s\"\n", arg);
 }
 
@@ -2494,7 +2509,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2545,7 +2560,10 @@ int main(int argc, char *argv[])
 						 quota_max_path_len);
 			break;
 		case 'Q':
-			set_quota(optarg);
+			set_quota(optarg, false);
+			break;
+		case 'q':
+			set_quota(optarg, true);
 			break;
 		case 'w':
 			set_timeout(optarg);
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index a772f3b8ea..ec52d8d3ff 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -268,6 +268,8 @@ extern int priv_domid;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
+extern int quota_memory_per_domain_soft;
+extern int quota_memory_per_domain_hard;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 5c79eed3dc..4242380886 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -76,6 +76,13 @@ struct domain
 	/* number of entry from this domain in the store */
 	int nbentry;
 
+	/* Amount of memory allocated for this domain. */
+	int memory;
+	bool soft_quota_reported;
+	bool hard_quota_reported;
+	time_t mem_last_msg;
+#define MEM_WARN_MINTIME_SEC 10
+
 	/* number of watch for this domain */
 	int nbwatch;
 
@@ -192,6 +199,9 @@ static bool domain_can_read(struct connection *conn)
 			return false;
 		if (conn->domain->nboutstanding >= quota_req_outstanding)
 			return false;
+		if (conn->domain->memory >= quota_memory_per_domain_hard &&
+		    quota_memory_per_domain_hard)
+			return false;
 	}
 
 	return (intf->req_cons != intf->req_prod);
@@ -982,6 +992,89 @@ int domain_entry(struct connection *conn)
 		: 0;
 }
 
+static bool domain_chk_quota(struct domain *domain, int mem)
+{
+	time_t now;
+
+	if (!domain || !domid_is_unprivileged(domain->domid) ||
+	    (domain->conn && domain->conn->is_ignored))
+		return false;
+
+	now = time(NULL);
+
+	if (mem >= quota_memory_per_domain_hard &&
+	    quota_memory_per_domain_hard) {
+		if (domain->hard_quota_reported)
+			return true;
+		syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n",
+		       domain->domid);
+		domain->mem_last_msg = now;
+		domain->hard_quota_reported = true;
+		return true;
+	}
+
+	if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) {
+		if (domain->hard_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->hard_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below hard memory quota again\n",
+			       domain->domid);
+		}
+		if (mem >= quota_memory_per_domain_soft &&
+		    quota_memory_per_domain_soft &&
+		    !domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = true;
+			syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n",
+			       domain->domid);
+		}
+		if (mem < quota_memory_per_domain_soft &&
+		    domain->soft_quota_reported) {
+			domain->mem_last_msg = now;
+			domain->soft_quota_reported = false;
+			syslog(LOG_INFO, "Domain %u below soft memory quota again\n",
+			       domain->domid);
+		}
+
+	}
+
+	return false;
+}
+
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
+{
+	struct domain *domain;
+
+	domain = find_domain_struct(domid);
+	if (domain) {
+		/*
+		 * domain_chk_quota() will print warning and also store whether
+		 * the soft/hard quota has been hit. So check no_quota_check
+		 * *after*.
+		 */
+		if (domain_chk_quota(domain, domain->memory + mem) &&
+		    !no_quota_check)
+			return ENOMEM;
+		domain->memory += mem;
+	} else {
+		/*
+		 * The domain the memory is to be accounted for should always
+		 * exist, as accounting is done either for a domain related to
+		 * the current connection, or for the domain owning a node
+		 * (which is always existing, as the owner of the node is
+		 * tested to exist and replaced by domid 0 if not).
+		 * So not finding the related domain MUST be an error in the
+		 * data base.
+		 */
+		errno = ENOENT;
+		corrupt(NULL, "Accounting called for non-existing domain %u\n",
+			domid);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
 void domain_watch_inc(struct connection *conn)
 {
 	if (!conn || !conn->domain)
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5937931314..d342e5e867 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -62,6 +62,26 @@ int domain_entry_inc(struct connection *conn, struct node *);
 void domain_entry_dec(struct connection *conn, struct node *);
 int domain_entry_fix(unsigned int domid, int num, bool update);
 int domain_entry(struct connection *conn);
+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check);
+
+/*
+ * domain_memory_add_chk(): to be used when memory quota should be checked.
+ * Not to be used when specifying a negative mem value, as lowering the used
+ * memory should always be allowed.
+ */
+static inline int domain_memory_add_chk(unsigned int domid, int mem)
+{
+	return domain_memory_add(domid, mem, false);
+}
+/*
+ * domain_memory_add_nochk(): to be used when memory quota should not be
+ * checked, e.g. when lowering memory usage, or in an error case for undoing
+ * a previous memory adjustment.
+ */
+static inline void domain_memory_add_nochk(unsigned int domid, int mem)
+{
+	domain_memory_add(domid, mem, true);
+}
 void domain_watch_inc(struct connection *conn);
 void domain_watch_dec(struct connection *conn);
 int domain_watch(struct connection *conn);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:13:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:13:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435886.689743 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcW-0005Ff-9i; Wed, 02 Nov 2022 12:13:24 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435886.689743; Wed, 02 Nov 2022 12:13:24 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcW-0005FV-6i; Wed, 02 Nov 2022 12:13:24 +0000
Received: by outflank-mailman (input) for mailman id 435886;
 Wed, 02 Nov 2022 12:13:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcV-0005FI-FR
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:23 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcV-0000tK-Ep
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:23 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcV-0001PN-E8
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:23 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=NS8tdcKGICzjJn2QmmWb1RCKJyIWXTO0f5CZXJj6bbQ=; b=bvSwuLvHm8fRacA5TBPxbcI0lr
	8c3c5qaszokbL5PTCdyWG/9sUhowGiF6g8TAKX+Y7KR50pK3FDGwz9g5SkDd5Ru1MwxIyVyQaKQvN
	wXyMYUnwDxvrgVjnaID79d/KxjAxXYByZXCeaQYcRvwKiAaIeUN4HJgx9D0pIRd/V9FQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: add memory accounting for responses
Message-Id: <E1oqCcV-0001PN-E8@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:13:23 +0000

commit f6d00133643a524d2138c9e3f192bbde719050ba
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:09 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add memory accounting for responses
    
    Add the memory accounting for queued responses.
    
    In case adding a watch event for a guest is causing the hard memory
    quota of that guest to be violated, the event is dropped. This will
    ensure that it is impossible to drive another guest past its memory
    quota by generating insane amounts of events for that guest. This is
    especially important for protecting driver domains from that attack
    vector.
    
    This is part of XSA-326 / CVE-2022-42315.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f03ad93b43..009eaa8e5f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -256,6 +256,8 @@ static void free_buffered_data(struct buffered_data *out,
 		}
 	}
 
+	domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr));
+
 	if (out->hdr.msg.type == XS_WATCH_EVENT) {
 		req = out->pend.req;
 		if (req) {
@@ -934,11 +936,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
 	bdata->timeout_msec = 0;
 	bdata->watch_event = false;
 
-	if (len <= DEFAULT_BUFFER_SIZE)
+	if (len <= DEFAULT_BUFFER_SIZE) {
 		bdata->buffer = bdata->default_buffer;
-	else {
+		/* Don't check quota, path might be used for returning error. */
+		domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
+	} else {
 		bdata->buffer = talloc_array(bdata, char, len);
-		if (!bdata->buffer) {
+		if (!bdata->buffer ||
+		    domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
 			send_error(conn, ENOMEM);
 			return;
 		}
@@ -1003,6 +1008,11 @@ void send_event(struct buffered_data *req, struct connection *conn,
 		}
 	}
 
+	if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) {
+		talloc_free(bdata);
+		return;
+	}
+
 	if (timeout_watch_event_msec && domain_is_unprivileged(conn)) {
 		bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec;
 		if (!conn->timeout_msec)
@@ -3012,6 +3022,12 @@ static void add_buffered_data(struct buffered_data *bdata,
 	 */
 	if (bdata->hdr.msg.type != XS_WATCH_EVENT)
 		domain_outstanding_inc(conn);
+	/*
+	 * We are restoring the state after Live-Update and the new quota may
+	 * be smaller. So ignore it. The limit will be applied for any resource
+	 * after the state has been fully restored.
+	 */
+	domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr));
 }
 
 void read_state_buffered_data(const void *ctx, struct connection *conn,
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:13:34 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:13:34 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435888.689747 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcg-0005Ib-BQ; Wed, 02 Nov 2022 12:13:34 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435888.689747; Wed, 02 Nov 2022 12:13:34 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcg-0005IP-8K; Wed, 02 Nov 2022 12:13:34 +0000
Received: by outflank-mailman (input) for mailman id 435888;
 Wed, 02 Nov 2022 12:13:33 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcf-0005IF-Ig
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:33 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcf-0000tU-I1
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:33 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcf-0001Ps-HJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:33 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=qSbhrnu1GSOiI2ddF111ombATSGiCc2genUKTGRRfpU=; b=lmyCe6H7Z5MnN4djvmaIG78x46
	m2p9jQu7pWEXgE/zZZZvf39BJdU7f840AkkUGL+4F6ctnNfI0lG+CIkDGS+qL8u11FwnOKAIA+b6k
	0qYUSofxEXZDS0hIG62ooX9Wterijennt0Ftw0QA2odoqsB1kNEDxr0J41OVCuN0p+Cc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: add memory accounting for watches
Message-Id: <E1oqCcf-0001Ps-HJ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:13:33 +0000

commit 7f9978a2cc37aaffab2fb09593bc598c0712a69b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add memory accounting for watches
    
    Add the memory accounting for registered watches.
    
    When a socket connection is destroyed, the associated watches are
    removed, too. In order to keep memory accounting correct the watches
    must be removed explicitly via a call of conn_delete_all_watches() from
    destroy_conn().
    
    This is part of XSA-326 / CVE-2022-42315.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c  |  1 +
 tools/xenstore/xenstored_watch.c | 13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 009eaa8e5f..1a5ba4aba8 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -459,6 +459,7 @@ static int destroy_conn(void *_conn)
 	}
 
 	conn_free_buffered_data(conn);
+	conn_delete_all_watches(conn);
 	list_for_each_entry(req, &conn->ref_list, list)
 		req->on_ref_list = false;
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 0755ffa375..fdf9b2d653 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -211,7 +211,7 @@ static int check_watch_path(struct connection *conn, const void *ctx,
 }
 
 static struct watch *add_watch(struct connection *conn, char *path, char *token,
-			       bool relative)
+			       bool relative, bool no_quota_check)
 {
 	struct watch *watch;
 
@@ -222,6 +222,9 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	watch->token = talloc_strdup(watch, token);
 	if (!watch->node || !watch->token)
 		goto nomem;
+	if (domain_memory_add(conn->id, strlen(path) + strlen(token),
+			      no_quota_check))
+		goto nomem;
 
 	if (relative)
 		watch->relative_path = get_implicit_path(conn);
@@ -265,7 +268,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (domain_watch(conn) > quota_nb_watch_per_domain)
 		return E2BIG;
 
-	watch = add_watch(conn, vec[0], vec[1], relative);
+	watch = add_watch(conn, vec[0], vec[1], relative, false);
 	if (!watch)
 		return errno;
 
@@ -296,6 +299,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	list_for_each_entry(watch, &conn->watches, list) {
 		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 			list_del(&watch->list);
+			domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+							  strlen(watch->token));
 			talloc_free(watch);
 			domain_watch_dec(conn);
 			send_ack(conn, XS_UNWATCH);
@@ -311,6 +316,8 @@ void conn_delete_all_watches(struct connection *conn)
 
 	while ((watch = list_top(&conn->watches, struct watch, list))) {
 		list_del(&watch->list);
+		domain_memory_add_nochk(conn->id, -strlen(watch->node) -
+						  strlen(watch->token));
 		talloc_free(watch);
 		domain_watch_dec(conn);
 	}
@@ -373,7 +380,7 @@ void read_state_watch(const void *ctx, const void *state)
 	if (!path)
 		barf("allocation error for read watch");
 
-	if (!add_watch(conn, path, token, relative))
+	if (!add_watch(conn, path, token, relative, true))
 		barf("error adding watch");
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:13:44 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:13:44 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435889.689750 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcq-0005LJ-Cb; Wed, 02 Nov 2022 12:13:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435889.689750; Wed, 02 Nov 2022 12:13:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCcq-0005LB-9p; Wed, 02 Nov 2022 12:13:44 +0000
Received: by outflank-mailman (input) for mailman id 435889;
 Wed, 02 Nov 2022 12:13:43 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcp-0005L3-Ld
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:43 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcp-0000te-L2
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:43 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcp-0001QH-KN
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:43 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=z/1DKvgBsGwzZ0usJhFyqtz0CEXJSnS3yy5nmAsZ45c=; b=bBP4PsVXtJxlzg3ZE50ZijnAFf
	snKYyvT36egz4NnhOFETCeNnzOYWS9RImsI9ri4rB8xa/HYEP6VvcV0EOGjCsakXjy9eJR2iAz+7x
	eMTAjmwU8c68f2aQJSM6iAxI6tvARKeX4myH0EAkuco3iHANgZgepAxXXazBVsE7HDGo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: add memory accounting for nodes
Message-Id: <E1oqCcp-0001QH-KN@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:13:43 +0000

commit 00e9e32d022be1afc144b75acdaeba8393e63315
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    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>
---
 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 1a5ba4aba8..f7f1e00c71 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -587,6 +587,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.
@@ -640,9 +751,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. */
@@ -711,12 +828,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;
 }
 
@@ -1218,7 +1332,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;
 	}
@@ -1291,6 +1405,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;
 
@@ -1299,17 +1414,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);
 
 	/*
@@ -1361,7 +1476,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;
 			}
 		}
@@ -2270,7 +2385,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);
 		}
 	}
 
@@ -3122,6 +3237,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 ec52d8d3ff..031a821358 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -176,6 +176,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 */
@@ -198,6 +203,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. */
@@ -301,6 +309,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 7bd41eb475..ace9a11d77 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;
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:13:54 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:13:54 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435890.689754 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCd0-0005Og-Fi; Wed, 02 Nov 2022 12:13:54 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435890.689754; Wed, 02 Nov 2022 12:13:54 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCd0-0005OY-Ck; Wed, 02 Nov 2022 12:13:54 +0000
Received: by outflank-mailman (input) for mailman id 435890;
 Wed, 02 Nov 2022 12:13:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcz-0005OR-OY
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcz-0000uE-Nw
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCcz-0001Qm-NJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:13:53 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5hqQ/VIlwfn83qsAssDFINV7CRxhO1birvhEj6QcRno=; b=2Vzc/4fikVV6RAR27ylQP6ovi8
	95IBysJ10DNMUhH4V/1wR9s8GBv+5uTUm0bP1XgHZUNT5INVk68SNwl1dG1YjY9qN3K6ws1TtkLCr
	03p0UNcQ8lMi/uXKzgZnGJkrzrjqNENwQ588J+ffWR2egNa37Q8EmCGFBFcxWZp6pZ6k=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: add exports for quota variables
Message-Id: <E1oqCcz-0001Qm-NJ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:13:53 +0000

commit 1da16d5990b5f7752657fca3e948f735177ea9ad
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add exports for quota variables
    
    Some quota variables are not exported via header files.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.h        | 5 +++++
 tools/xenstore/xenstored_transaction.c | 1 -
 tools/xenstore/xenstored_watch.c       | 2 --
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 031a821358..f7c37fe3b5 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -273,6 +273,11 @@ extern TDB_CONTEXT *tdb_ctx;
 extern int dom0_domid;
 extern int dom0_event;
 extern int priv_domid;
+extern int quota_nb_watch_per_domain;
+extern int quota_max_transaction;
+extern int quota_max_entry_size;
+extern int quota_nb_perms_per_node;
+extern int quota_max_path_len;
 extern int quota_nb_entry_per_domain;
 extern int quota_req_outstanding;
 extern int quota_trans_nodes;
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index ace9a11d77..28774813de 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -175,7 +175,6 @@ struct transaction
 	bool fail;
 };
 
-extern int quota_max_transaction;
 uint64_t generation;
 
 static struct accessed_node *find_accessed_node(struct transaction *trans,
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index fdf9b2d653..85362bcce3 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -31,8 +31,6 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 
-extern int quota_nb_watch_per_domain;
-
 struct watch
 {
 	/* Watches on this connection */
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:14:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:14:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435891.689759 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdA-0005RU-Ig; Wed, 02 Nov 2022 12:14:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435891.689759; Wed, 02 Nov 2022 12:14:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdA-0005RL-EP; Wed, 02 Nov 2022 12:14:04 +0000
Received: by outflank-mailman (input) for mailman id 435891;
 Wed, 02 Nov 2022 12:14:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCd9-0005RF-Ri
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCd9-0000uc-R6
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCd9-0001RN-QP
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=UxvmBZeLd5BRMn15apNOWweRU6j4lDdZEJf+pGrpR1g=; b=Fj4V29itfr4T0K4hLnQbus7RGG
	HVDZyK7oDvTdlRQfgG9Ogf5RpBY9OiEojcTuZ807O/Vnmd9hd7RZDX8n8ZsNi3dcPbr0cCfnQtgeU
	WZYqmJQQIrfaCh/OMgNpuMGqrzywt22Fqr/1G/bzSVTAtVh0ippg1OaMj1DeMMDAn3JE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: add control command for setting and showing quota
Message-Id: <E1oqCd9-0001RN-QP@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:14:03 +0000

commit 9c484bef83496b683b0087e3bd2a560da4aa37af
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add control command for setting and showing quota
    
    Add a xenstore-control command "quota" to:
    - show current quota settings
    - change quota settings
    - show current quota related values of a domain
    
    Note that in the case the new quota is lower than existing one,
    Xenstored may continue to handle requests from a domain exceeding the
    new limit (depends on which one has been broken) and the amount of
    resource used will not change. However the domain will not be able to
    create more resource (associated to the quota) until it is back to below
    the limit.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 docs/misc/xenstore.txt             |  11 ++++
 tools/xenstore/xenstored_control.c | 111 +++++++++++++++++++++++++++++++++++++
 tools/xenstore/xenstored_domain.c  |  33 +++++++++++
 tools/xenstore/xenstored_domain.h  |   2 +
 4 files changed, 157 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 4bc262fd5d..988ef89cba 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -410,6 +410,17 @@ CONTROL			<command>|[<parameters>|]
 	print|<string>
 		print <string> to syslog (xenstore runs as daemon) or
 		to console (xenstore runs as stubdom)
+	quota|[set <name> <val>|<domid>]
+		without parameters: print the current quota settings
+		with "set <name> <val>": set the quota <name> to new value
+		<val> (The admin should make sure all the domain usage is
+		below the quota. If it is not, then Xenstored may continue to
+		handle requests from the domain as long as the resource
+		violating the new quota setting isn't increased further)
+		with "<domid>": print quota related accounting data for
+		the domain <domid>
+	quota-soft|[set <name> <val>]
+		like the "quota" command, but for soft-quota.
 	help			<supported-commands>
 		return list of supported commands for CONTROL
 
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 61bcbc069d..264bb39d7b 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -196,6 +196,115 @@ static int do_control_log(void *ctx, struct connection *conn,
 	return 0;
 }
 
+struct quota {
+	const char *name;
+	int *quota;
+	const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+	{ "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+	{ "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+	{ "transactions", &quota_max_transaction, "Transactions per domain" },
+	{ "outstanding", &quota_req_outstanding,
+		"Outstanding requests per domain" },
+	{ "transaction-nodes", &quota_trans_nodes,
+		"Max. number of accessed nodes per transaction" },
+	{ "memory", &quota_memory_per_domain_hard,
+		"Total Xenstore memory per domain (error level)" },
+	{ "node-size", &quota_max_entry_size, "Max. size of a node" },
+	{ "path-max", &quota_max_path_len, "Max. length of a node path" },
+	{ "permissions", &quota_nb_perms_per_node,
+		"Max. number of permissions per node" },
+	{ NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+	{ "memory", &quota_memory_per_domain_soft,
+		"Total Xenstore memory per domain (warning level)" },
+	{ NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+			      const struct quota *quotas)
+{
+	char *resp;
+	unsigned int i;
+
+	resp = talloc_strdup(ctx, "Quota settings:\n");
+	if (!resp)
+		return ENOMEM;
+
+	for (i = 0; quotas[i].quota; i++) {
+		resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+					      quotas[i].name, *quotas[i].quota,
+					      quotas[i].descr);
+		if (!resp)
+			return ENOMEM;
+	}
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+		     char **vec, int num, const struct quota *quotas)
+{
+	unsigned int i;
+	int val;
+
+	if (num != 2)
+		return EINVAL;
+
+	val = atoi(vec[1]);
+	if (val < 1)
+		return EINVAL;
+
+	for (i = 0; quotas[i].quota; i++) {
+		if (!strcmp(vec[0], quotas[i].name)) {
+			*quotas[i].quota = val;
+			send_ack(conn, XS_CONTROL);
+			return 0;
+		}
+	}
+
+	return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+		     char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, hard_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+	return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+			      char **vec, int num)
+{
+	if (num == 0)
+		return quota_show_current(ctx, conn, soft_quotas);
+
+	if (!strcmp(vec[0], "set"))
+		return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+	return EINVAL;
+}
+
 #ifdef __MINIOS__
 static int do_control_memreport(void *ctx, struct connection *conn,
 				char **vec, int num)
@@ -847,6 +956,8 @@ static struct cmd_s cmds[] = {
 	{ "memreport", do_control_memreport, "[<file>]" },
 #endif
 	{ "print", do_control_print, "<string>" },
+	{ "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+	{ "quota-soft", do_control_quota_s, "[set <name> <val>]" },
 	{ "help", do_control_help, "" },
 };
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 4242380886..983b348ee5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -345,6 +346,38 @@ static struct domain *find_domain_struct(unsigned int domid)
 	return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid)
+{
+	struct domain *d = find_domain_struct(domid);
+	char *resp;
+	int ta;
+
+	if (!d)
+		return ENOENT;
+
+	ta = d->conn ? d->conn->transaction_started : 0;
+	resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+	if (!resp)
+		return ENOMEM;
+
+#define ent(t, e) \
+	resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+	if (!resp) return ENOMEM
+
+	ent(nodes, d->nbentry);
+	ent(watches, d->nbwatch);
+	ent(transactions, ta);
+	ent(outstanding, d->nboutstanding);
+	ent(memory, d->memory);
+
+#undef ent
+
+	send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+	return 0;
+}
+
 static struct domain *alloc_domain(const void *context, unsigned int domid)
 {
 	struct domain *domain;
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index d342e5e867..5b86a92e1b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -88,6 +88,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+		     unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:14:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:14:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435892.689763 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdK-0005UT-J6; Wed, 02 Nov 2022 12:14:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435892.689763; Wed, 02 Nov 2022 12:14:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdK-0005UJ-G4; Wed, 02 Nov 2022 12:14:14 +0000
Received: by outflank-mailman (input) for mailman id 435892;
 Wed, 02 Nov 2022 12:14:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdJ-0005UC-Ug
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdJ-0000um-U4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdJ-0001Rq-TI
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=uuBuAzbLxGcXX5tsPNyAS+cdQWKWkS4vyI5QxE7Qq5I=; b=ZQI2cWwo1RDIInedvrdY7YgQ+B
	zEdKWzeuHWkAErJWXYBTdC5vmELw6gFrA5FdQopMoC8y1uuR9jjqeKYcQDdoV0iqlQq0Aohqj4OVW
	HLmX+xJu8KEwJH0pbWsbFPCoOLVFTQQY5AIL7y7ud4l5cWwbbujxv+CXOnQJfDNqrSHU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
Message-Id: <E1oqCdJ-0001Rq-TI@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:14:13 +0000

commit 84734955d4bf629ba459a74773afcde50a52236f
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:01 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in
    
    We currently have 2 different set of defaults in upstream Xen git tree:
    * defined in the source code, only used if there is no config file
    * defined in the oxenstored.conf.in upstream Xen
    
    An oxenstored.conf file is not mandatory, and if missing, maxrequests in
    particular has an unsafe default.
    
    Resync the defaults from oxenstored.conf.in into the source code.
    
    This is part of XSA-326 / CVE-2022-42316.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/xenstored/define.ml | 6 +++---
 tools/ocaml/xenstored/quota.ml  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ebe18b8e31..6b06f80859 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -21,9 +21,9 @@ let xs_daemon_socket = Paths.xen_run_stored ^ "/socket"
 
 let default_config_dir = Paths.xen_config_dir
 
-let maxwatch = ref (50)
-let maxtransaction = ref (20)
-let maxrequests = ref (-1)   (* maximum requests per transaction *)
+let maxwatch = ref (100)
+let maxtransaction = ref (10)
+let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
index abcac91280..6e3d6401ae 100644
--- a/tools/ocaml/xenstored/quota.ml
+++ b/tools/ocaml/xenstored/quota.ml
@@ -20,8 +20,8 @@ exception Transaction_opened
 
 let warn fmt = Logging.warn "quota" fmt
 let activate = ref true
-let maxent = ref (10000)
-let maxsize = ref (4096)
+let maxent = ref (1000)
+let maxsize = ref (2048)
 
 type t = {
 	maxent: int;               (* max entities per domU *)
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:14:25 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:14:25 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435893.689766 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdV-0005XO-KM; Wed, 02 Nov 2022 12:14:25 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435893.689766; Wed, 02 Nov 2022 12:14:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdV-0005XG-Hg; Wed, 02 Nov 2022 12:14:25 +0000
Received: by outflank-mailman (input) for mailman id 435893;
 Wed, 02 Nov 2022 12:14:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdU-0005X6-1M
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdU-0000ut-0f
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdU-0001SO-02
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Ye465ocxnfskPxOMa5h91sH2Ey1jbERDH7/vr280LDI=; b=fvJaNGrHwGlD7DcJWS8gLM8LDs
	XzAnqXvkfVnKyOSOgWIxa4V9yCrIzn9t/X51XIsvy+3mp5j6MHQwUbumS29pSOS8dB8Stv/PLocmH
	dpSRVkVNhONSI3u2rUY5+4VQf0unjf7QOqRZqbIXGRyH0J7/lOS3pI2QfWbh6qrn6xI4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml/xenstored: Check for maxrequests before performing operations
Message-Id: <E1oqCdU-0001SO-02@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:14:24 +0000

commit 329f4d1a6535c6c5a34025ca0d03fc5c7228fcff
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Thu Jul 28 17:08:15 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    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>
---
 tools/ocaml/xenstored/process.ml     |  4 +++-
 tools/ocaml/xenstored/transaction.ml | 16 ++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 86eed02413..d0400419ab 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -389,6 +389,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"
@@ -682,9 +683,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"
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
index 17b1bdf2ea..294143e233 100644
--- a/tools/ocaml/xenstored/transaction.ml
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -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
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:14:35 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:14:35 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435894.689771 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdf-0005Zy-Ma; Wed, 02 Nov 2022 12:14:35 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435894.689771; Wed, 02 Nov 2022 12:14:35 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdf-0005Zq-JD; Wed, 02 Nov 2022 12:14:35 +0000
Received: by outflank-mailman (input) for mailman id 435894;
 Wed, 02 Nov 2022 12:14:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCde-0005Zc-5d
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCde-0000ux-3X
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCde-0001TB-2q
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=QxknssW3rdIwwOfAGL7T63qmhPy3yX0GG8mGOsMcI18=; b=ggHiIkmwuxWREBa9yn2CVnAzPQ
	hbMCzm18RUoATxb3yzHcoO4QT3tbKok+QIqwHF9RBTrt3NRF0/CbNhlHJWR3+RuU2okyRSoPhXAYL
	nV9L9oXPjO0UesOl3G+4u/AOK+WIx2ge/40Aully5qFTff8zsY7n/mwPknaEcUWvyw9U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml: GC parameter tuning
Message-Id: <E1oqCde-0001TB-2q@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:14:34 +0000

commit 4a8bacff20b857ca0d628ef5525877ade11f2a42
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:07 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml: GC parameter tuning
    
    By default the OCaml garbage collector would return memory to the OS only
    after unused memory is 5x live memory.  Tweak this to 120% instead, which
    would match the major GC speed.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/xenstored/define.ml    |  1 +
 tools/ocaml/xenstored/xenstored.ml | 64 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index 6b06f80859..ba63a8147e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -25,6 +25,7 @@ let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
 
+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
 let conflict_max_history_seconds = ref 0.05
 let conflict_rate_limit_is_aggregate = ref true
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index acc7290627..3a932f54a6 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -104,6 +104,7 @@ let parse_config filename =
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
 		("quota-path-max", Config.Set_int Define.path_max);
+		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
 		("persistent", Config.Set_bool Disk.enable);
 		("xenstored-log-file", Config.String Logging.set_xenstored_log_destination);
@@ -265,6 +266,67 @@ let to_file store cons fds file =
 	        (fun () -> close_out channel)
 end
 
+(*
+	By default OCaml's GC only returns memory to the OS when it exceeds a
+	configurable 'max overhead' setting.
+	The default is 500%, that is 5/6th of the OCaml heap needs to be free
+	and only 1/6th live for a compaction to be triggerred that would
+	release memory back to the OS.
+	If the limit is not hit then the OCaml process can reuse that memory
+	for its own purposes, but other processes won't be able to use it.
+
+	There is also a 'space overhead' setting that controls how much work
+	each major GC slice does, and by default aims at having no more than
+	80% or 120% (depending on version) garbage values compared to live
+	values.
+	This doesn't have as much relevance to memory returned to the OS as
+	long as space_overhead <= max_overhead, because compaction is only
+	triggerred at the end of major GC cycles.
+
+	The defaults are too large once the program starts using ~100MiB of
+	memory, at which point ~500MiB would be unavailable to other processes
+	(which would be fine if this was the main process in this VM, but it is
+	not).
+
+	Max overhead can also be set to 0, however this is for testing purposes
+	only (setting it lower than 'space overhead' wouldn't help because the
+	major GC wouldn't run fast enough, and compaction does have a
+	performance cost: we can only compact contiguous regions, so memory has
+	to be moved around).
+
+	Max overhead controls how often the heap is compacted, which is useful
+	if there are burst of activity followed by long periods of idle state,
+	or if a domain quits, etc. Compaction returns memory to the OS.
+
+	wasted = live * space_overhead / 100
+
+	For globally overriding the GC settings one can use OCAMLRUNPARAM,
+	however we provide a config file override to be consistent with other
+	oxenstored settings.
+
+	One might want to dynamically adjust the overhead setting based on used
+	memory, i.e. to use a fixed upper bound in bytes, not percentage. However
+	measurements show that such adjustments increase GC overhead massively,
+	while still not guaranteeing that memory is returned any more quickly
+	than with a percentage based setting.
+
+	The allocation policy could also be tweaked, e.g. first fit would reduce
+	fragmentation and thus memory usage, but the documentation warns that it
+	can be sensibly slower, and indeed one of our own testcases can trigger
+	such a corner case where it is multiple times slower, so it is best to keep
+	the default allocation policy (next-fit/best-fit depending on version).
+
+	There are other tweaks that can be attempted in the future, e.g. setting
+	'ulimit -v' to 75% of RAM, however getting the kernel to actually return
+	NULL from allocations is difficult even with that setting, and without a
+	NULL the emergency GC won't be triggerred.
+	Perhaps cgroup limits could help, but for now tweak the safest only.
+*)
+
+let tweak_gc () =
+	Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead }
+
+
 let _ =
 	let cf = do_argv in
 	let pidfile =
@@ -274,6 +336,8 @@ let _ =
 			default_pidfile
 		in
 
+	tweak_gc ();
+
 	(try
 		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
 	with _ ->
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:14:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:14:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435895.689774 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdp-0005d0-Pi; Wed, 02 Nov 2022 12:14:45 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435895.689774; Wed, 02 Nov 2022 12:14:45 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdp-0005cs-Mf; Wed, 02 Nov 2022 12:14:45 +0000
Received: by outflank-mailman (input) for mailman id 435895;
 Wed, 02 Nov 2022 12:14:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdo-0005cf-7F
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdo-0000v8-6a
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdo-0001Tm-5v
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=r0c7iKJjTgqxGF1GC1IbYiepvD6IcbREcYGYu2Kduv0=; b=s2oHus6/+/AwaZ+tQ5TfNQn1IL
	ADBZi66WsuFmSvE561xsIMA3mk+UG0n3ItRrmzeUbXw7v47rM/i0EEKw5E4Y20dfnKO4MErVdI8z6
	MQV5JXmLxEha3VaIXerW0RK5LxB4UZsb/Du2ZbK4S4MBMhJPDj/rWqE4er07k3HeKNx0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml: Change Xb.input to return Packet.t option
Message-Id: <E1oqCdo-0001Tm-5v@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:14:44 +0000

commit c0a86a462721008eca5ff733660de094d3c34bc7
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:02 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml: Change Xb.input to return Packet.t option
    
    The queue here would only ever hold at most one element.  This will simplify
    follow-up patches.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/libs/xb/xb.ml           | 18 +++++-------------
 tools/ocaml/libs/xb/xb.mli          |  5 +----
 tools/ocaml/libs/xs/xsraw.ml        | 20 ++++++--------------
 tools/ocaml/xenstored/connection.ml |  4 +---
 tools/ocaml/xenstored/process.ml    | 15 +++++++--------
 5 files changed, 20 insertions(+), 42 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 8404ddd8a6..165fd4a1ed 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 type t =
 {
 	backend: backend;
-	pkt_in: Packet.t Queue.t;
 	pkt_out: Packet.t Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
@@ -62,7 +61,6 @@ let reconnect t = match t.backend with
 		Xs_ring.close backend.mmap;
 		backend.eventchn_notify ();
 		(* Clear our old connection state *)
-		Queue.clear t.pkt_in;
 		Queue.clear t.pkt_out;
 		t.partial_in <- init_partial_in ();
 		t.partial_out <- ""
@@ -124,7 +122,6 @@ let output con =
 
 (* NB: can throw Reconnect *)
 let input con =
-	let newpacket = ref false in
 	let to_read =
 		match con.partial_in with
 		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
@@ -143,21 +140,19 @@ let input con =
 		if Partial.to_complete partial_pkt = 0 then (
 			let pkt = Packet.of_partialpkt partial_pkt in
 			con.partial_in <- init_partial_in ();
-			Queue.push pkt con.pkt_in;
-			newpacket := true
-		)
+			Some pkt
+		) else None
 	| NoHdr (i, buf)      ->
 		(* we complete the partial header *)
 		if sz > 0 then
 			Bytes.blit b 0 buf (Partial.header_size () - i) sz;
 		con.partial_in <- if sz = i then
-			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf)
-	);
-	!newpacket
+			HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf);
+		None
+	)
 
 let newcon backend = {
 	backend = backend;
-	pkt_in = Queue.create ();
 	pkt_out = Queue.create ();
 	partial_in = init_partial_in ();
 	partial_out = "";
@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con
 
 let peek_output con = Queue.peek con.pkt_out
 
-let input_len con = Queue.length con.pkt_in
-let has_in_packet con = Queue.length con.pkt_in > 0
-let get_in_packet con = Queue.pop con.pkt_in
 let has_partial_input con = match con.partial_in with
 	| HaveHdr _ -> true
 	| NoHdr (n, _) -> n < Partial.header_size ()
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 794e35bb34..91c682162c 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int
 val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
-val input : t -> bool
+val input : t -> Packet.t option
 val newcon : backend -> t
 val open_fd : Unix.file_descr -> t
 val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
@@ -89,10 +89,7 @@ val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
 val peek_output : t -> Packet.t
-val input_len : t -> int
-val has_in_packet : t -> bool
 val has_partial_input : t -> bool
-val get_in_packet : t -> Packet.t
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index d982fb24db..451f8b38db 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -94,26 +94,18 @@ let pkt_send con =
 	done
 
 (* receive one packet - can sleep *)
-let pkt_recv con =
-	let workdone = ref false in
-	while not !workdone
-	do
-		workdone := Xb.input con.xb
-	done;
-	Xb.get_in_packet con.xb
+let rec pkt_recv con =
+	match Xb.input con.xb with
+	| Some packet -> packet
+	| None -> pkt_recv con
 
 let pkt_recv_timeout con timeout =
 	let fd = Xb.get_fd con.xb in
 	let r, _, _ = Unix.select [ fd ] [] [] timeout in
 	if r = [] then
 		true, None
-	else (
-		let workdone = Xb.input con.xb in
-		if workdone then
-			false, (Some (Xb.get_in_packet con.xb))
-		else
-			false, None
-	)
+	else
+		false, Xb.input con.xb
 
 let queue_watchevent con data =
 	let ls = split_string ~limit:2 '\000' data in
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 64180bb2d5..3f6a8f1ad0 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -277,9 +277,7 @@ let get_transaction con tid =
 	Hashtbl.find con.transactions tid
 
 let do_input con = Xenbus.Xb.input con.xb
-let has_input con = Xenbus.Xb.has_in_packet con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
-let pop_in con = Xenbus.Xb.get_in_packet con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
 let has_output con = Xenbus.Xb.has_output con.xb
@@ -307,7 +305,7 @@ let is_bad con = match con.dom with None -> false | Some dom -> Domain.is_bad_do
    Restrictions below can be relaxed once xenstored learns to dump more
    of its live state in a safe way *)
 let has_extra_connection_data con =
-	let has_in = has_input con || has_partial_input con in
+	let has_in = has_partial_input con in
 	let has_out = has_output con in
 	let has_nondefault_perms = make_perm con.dom <> con.perm in
 	has_in || has_out
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index d0400419ab..50ef05be41 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -195,10 +195,9 @@ let parse_live_update args =
 			| _ when Unix.gettimeofday () < t.deadline -> false
 			| l ->
 				warn "timeout reached: have to wait, migrate or shutdown %d domains:" (List.length l);
-				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, in: %b, out: %b, perm: %s"
+				let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, out: %b, perm: %s"
 					(Connection.get_domstr con)
 					(Connection.number_of_transactions con)
-					(Connection.has_input con)
 					(Connection.has_output con)
 					(Connection.get_perm con |> Perms.Connection.to_string)
 					) l in
@@ -707,16 +706,17 @@ let do_input store cons doms con =
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
-			false
+			None
 		| Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
-			false
+			None
 	in
 
-	if newpacket then (
-		let packet = Connection.pop_in con in
+	match newpacket with
+	| None -> ()
+	| Some packet ->
 		let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in
 		let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in
 
@@ -726,8 +726,7 @@ let do_input store cons doms con =
 		         (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *)
 		process_packet ~store ~cons ~doms ~con ~req;
 		write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
-		Connection.incr_ops con;
-	)
+		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
 	if Connection.has_output con then (
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:14:55 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:14:55 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435896.689778 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdz-0005fj-Qt; Wed, 02 Nov 2022 12:14:55 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435896.689778; Wed, 02 Nov 2022 12:14:55 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCdz-0005fc-OC; Wed, 02 Nov 2022 12:14:55 +0000
Received: by outflank-mailman (input) for mailman id 435896;
 Wed, 02 Nov 2022 12:14:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdy-0005fF-9y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdy-0000va-9N
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCdy-0001Ud-8n
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:14:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=JTaBbwu5kRh9Cul7uM6nqoq77xfVnBw7tLel+fdaOXQ=; b=gTo+gc2dvHSPt5Dai7WG9T85nF
	tO6zmByT/5KtcK/Mgd2GCsRcCFgOqdxlvobZVnVR+xncKrsAy4eVrwkld8LUDs+Gpi0+wQBcmi9xb
	UTh9DH8FEHgQUVXTGdBUbvvjgFEoa/MRd2bkJLEw+8HbHAnO2/FYmrUnqVyLx3+hUACE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml/xb: Add BoundedQueue
Message-Id: <E1oqCdy-0001Ud-8n@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:14:54 +0000

commit 19171fb5d888b4467a7073e8febc5e05540956e9
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:03 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml/xb: Add BoundedQueue
    
    Ensures we cannot store more than [capacity] elements in a [Queue].  Replacing
    all Queue with this module will then ensure at compile time that all Queues
    are correctly bound checked.
    
    Each element in the queue has a class with its own limits.  This, in a
    subsequent change, will ensure that command responses can proceed during a
    flood of watch events.
    
    No functional change.
    
    This is part of XSA-326.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/libs/xb/xb.ml | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 165fd4a1ed..4197a3888a 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -17,6 +17,98 @@
 module Op = struct include Op end
 module Packet = struct include Packet end
 
+module BoundedQueue : sig
+	type ('a, 'b) t
+
+	(** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements.
+	    This is burst capacity, each element is further classified according to [classify],
+	    and each class can have its own [limit].
+	    [capacity] is enforced as an overall limit.
+	    The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class,
+	    in which case those elements are considered to use "burst capacity".
+	  *)
+	val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t
+
+	(** [clear q] discards all elements from [q] *)
+	val clear: ('a, 'b) t -> unit
+
+	(** [can_push q] when [length q < capacity].	*)
+	val can_push: ('a, 'b) t -> 'b -> bool
+
+	(** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *)
+	val push: 'a -> ('a, 'b) t -> unit option
+
+	(** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *)
+	val pop: ('a, 'b) t -> 'a
+
+	(** [peek q] returns the first element in [q], or raises [Queue.Empty].  *)
+	val peek : ('a, 'b) t -> 'a
+
+	(** [length q] returns the current number of elements in [q] *)
+	val length: ('a, 'b) t -> int
+
+	(** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *)
+	val debug: ('b -> string) -> (_, 'b) t -> string
+end = struct
+	type ('a, 'b) t =
+		{ q: 'a Queue.t
+		; capacity: int
+		; classify: 'a -> 'b
+		; limit: 'b -> int
+		; class_count: ('b, int) Hashtbl.t
+		}
+
+	let create ~capacity ~classify ~limit =
+		{ capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 }
+
+	let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0
+
+	let can_push_internal t classification class_count =
+		Queue.length t.q < t.capacity && class_count < t.limit classification
+
+	let ok = Some ()
+
+	let push e t =
+		let classification = t.classify e in
+		let class_count = get_count t classification in
+		if can_push_internal t classification class_count then begin
+			Queue.push e t.q;
+			Hashtbl.replace t.class_count classification (class_count + 1);
+			ok
+		end
+		else
+			None
+
+	let can_push t classification =
+		can_push_internal t classification @@ get_count t classification
+
+	let clear t =
+		Queue.clear t.q;
+		Hashtbl.reset t.class_count
+
+	let pop t =
+		let e = Queue.pop t.q in
+		let classification = t.classify e in
+		let () = match get_count t classification - 1 with
+		| 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *)
+		| n -> Hashtbl.replace t.class_count classification n
+		in
+		e
+
+	let peek t = Queue.peek t.q
+	let length t = Queue.length t.q
+
+	let debug string_of_class t =
+		let b = Buffer.create 128 in
+		Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity;
+		Hashtbl.iter (fun packet_class count ->
+			Printf.bprintf b "	%s: %d" (string_of_class packet_class) count
+		) t.class_count;
+		Printf.bprintf b "}";
+		Buffer.contents b
+end
+
+
 exception End_of_file
 exception Eagain
 exception Noent
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:15:05 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:15:05 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435897.689782 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCe9-0005mm-T4; Wed, 02 Nov 2022 12:15:05 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435897.689782; Wed, 02 Nov 2022 12:15:05 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCe9-0005mN-Ps; Wed, 02 Nov 2022 12:15:05 +0000
Received: by outflank-mailman (input) for mailman id 435897;
 Wed, 02 Nov 2022 12:15:04 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCe8-0005iI-DL
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:04 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCe8-0000wG-Ch
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCe8-0001VP-Bt
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=cMYP+PBn4ruQc/dkvJV2W3qMiUYZozNJ8TNqVGKmpD0=; b=vvOu0q1cmr+2LQuPmMVGbnzdqh
	Pej4A89TTC2Upl3lUVNG55c1ad20F6TAv5QRZLlnnHQf7VqVu3+odia5KWzby7QY75WP1W527T9cN
	Ts3ZUktMEMHV0ZeLvCzHufj7QFYk3pSTB84iy++5CQXC7ey71uCW3ZB1aWvENEr+xosI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml: Limit maximum in-flight requests / outstanding replies
Message-Id: <E1oqCe8-0001VP-Bt@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:15:04 +0000

commit 9284ae0c40fb5b9606947eaaec23dc71d0540e96
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:04 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml: Limit maximum in-flight requests / outstanding replies
    
    Introduce a limit on the number of outstanding reply packets in the xenbus
    queue.  This limits the number of in-flight requests: when the output queue is
    full we'll stop processing inputs until the output queue has room again.
    
    To avoid a busy loop on the Unix socket we only add it to the watched input
    file descriptor set if we'd be able to call `input` on it.  Even though Dom0
    is trusted and exempt from quotas a flood of events might cause a backlog
    where events are produced faster than daemons in Dom0 can consume them, which
    could lead to an unbounded queue size and OOM.
    
    Therefore the xenbus queue limit must apply to all connections, Dom0 is not
    exempt from it, although if everything works correctly it will eventually
    catch up.
    
    This prevents a malicious guest from sending more commands while it has
    outstanding watch events or command replies in its input ring.  However if it
    can cause the generation of watch events by other means (e.g. by Dom0, or
    another cooperative guest) and stop reading its own ring then watch events
    would've queued up without limit.
    
    The xenstore protocol doesn't have a back-pressure mechanism, and doesn't
    allow dropping watch events.  In fact, dropping watch events is known to break
    some pieces of normal functionality.  This leaves little choice to safely
    implement the xenstore protocol without exposing the xenstore daemon to
    out-of-memory attacks.
    
    Implement the fix as pipes with bounded buffers:
    * Use a bounded buffer for watch events
    * The watch structure will have a bounded receiving pipe of watch events
    * The source will have an "overflow" pipe of pending watch events it couldn't
      deliver
    
    Items are queued up on one end and are sent as far along the pipe as possible:
    
      source domain -> watch -> xenbus of target -> xenstore ring/socket of target
    
    If the pipe is "full" at any point then back-pressure is applied and we prevent
    more items from being queued up.  For the source domain this means that we'll
    stop accepting new commands as long as its pipe buffer is not empty.
    
    Before we try to enqueue an item we first check whether it is possible to send
    it further down the pipe, by attempting to recursively flush the pipes. This
    ensures that we retain the order of events as much as possible.
    
    We might break causality of watch events if the target domain's queue is full
    and we need to start using the watch's queue.  This is a breaking change in
    the xenstore protocol, but only for domains which are not processing their
    incoming ring as expected.
    
    When a watch is deleted its entire pending queue is dropped (no code is needed
    for that, because it is part of the 'watch' type).
    
    There is a cache of watches that have pending events that we attempt to flush
    at every cycle if possible.
    
    Introduce 3 limits here:
    * quota-maxwatchevents on watch event destination: when this is hit the
      source will not be allowed to queue up more watch events.
    * quota-maxoustanding which is the number of responses not read from the ring:
      once exceeded, no more inputs are processed until all outstanding replies
      are consumed by the client.
    * overflow queue on the watch event source: all watches that cannot be stored
      on destination are queued up here, a single command can trigger multiple
      watches (e.g. due to recursion).
    
    The overflow queue currently doesn't have an upper bound, it is difficult to
    accurately calculate one as it depends on whether you are Dom0 and how many
    watches each path has registered and how many watch events you can trigger
    with a single command (e.g. a commit).  However these events were already
    using memory, this just moves them elsewhere, and as long as we correctly
    block a domain it shouldn't result in unbounded memory usage.
    
    Note that Dom0 is not excluded from these checks, it is important that Dom0 is
    especially not excluded when it is the source, since there are many ways in
    which a guest could trigger Dom0 to send it watch events.
    
    This should protect against malicious frontends as long as the backend follows
    the PV xenstore protocol and only exposes paths needed by the frontend, and
    changes those paths at most once as a reaction to guest events, or protocol
    state.
    
    The queue limits are per watch, and per domain-pair, so even if one
    communication channel would be "blocked", others would keep working, and the
    domain itself won't get blocked as long as it doesn't overflow the queue of
    watch events.
    
    Similarly a malicious backend could cause the frontend to get blocked, but
    this watch queue protects the frontend as well as long as it follows the PV
    protocol.  (Although note that protection against malicious backends is only a
    best effort at the moment)
    
    This is part of XSA-326 / CVE-2022-42318.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/libs/xb/xb.ml                |  61 ++++++++++--
 tools/ocaml/libs/xb/xb.mli               |  11 ++-
 tools/ocaml/libs/xs/queueop.ml           |  25 ++---
 tools/ocaml/libs/xs/xsraw.ml             |   4 +-
 tools/ocaml/xenstored/connection.ml      | 155 ++++++++++++++++++++++++++++---
 tools/ocaml/xenstored/connections.ml     |  57 +++++++++---
 tools/ocaml/xenstored/define.ml          |   7 ++
 tools/ocaml/xenstored/oxenstored.conf.in |   2 +
 tools/ocaml/xenstored/process.ml         |  31 +++++--
 tools/ocaml/xenstored/xenstored.ml       |   2 +
 10 files changed, 296 insertions(+), 59 deletions(-)

diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml
index 4197a3888a..b292ed7a87 100644
--- a/tools/ocaml/libs/xb/xb.ml
+++ b/tools/ocaml/libs/xb/xb.ml
@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap
 
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
 
+(*
+	separate capacity reservation for replies and watch events:
+	this allows a domain to keep working even when under a constant flood of
+	watch events
+*)
+type capacity = { maxoutstanding: int; maxwatchevents: int }
+
+module Queue = BoundedQueue
+
+type packet_class =
+	| CommandReply
+	| Watchevent
+
+let string_of_packet_class = function
+	| CommandReply -> "command_reply"
+	| Watchevent -> "watch_event"
+
 type t =
 {
 	backend: backend;
-	pkt_out: Packet.t Queue.t;
+	pkt_out: (Packet.t, packet_class) Queue.t;
 	mutable partial_in: partial_buf;
 	mutable partial_out: string;
+	capacity: capacity
 }
 
+let to_read con =
+	match con.partial_in with
+		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
+		| NoHdr   (i, _)    -> i
+
+let debug t =
+	Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s"
+		(to_read t)
+		(String.length t.partial_out)
+		(Queue.length t.pkt_out)
+		(BoundedQueue.debug string_of_packet_class t.pkt_out)
+
 let init_partial_in () = NoHdr
 	(Partial.header_size (), Bytes.make (Partial.header_size()) '\000')
 
@@ -199,7 +229,8 @@ let output con =
 	let s = if String.length con.partial_out > 0 then
 			con.partial_out
 		else if Queue.length con.pkt_out > 0 then
-			Packet.to_string (Queue.pop con.pkt_out)
+			let pkt = Queue.pop con.pkt_out in
+			Packet.to_string pkt
 		else
 			"" in
 	(* send data from s, and save the unsent data to partial_out *)
@@ -212,12 +243,15 @@ let output con =
 	(* after sending one packet, partial is empty *)
 	con.partial_out = ""
 
+(* we can only process an input packet if we're guaranteed to have room
+   to store the response packet *)
+let can_input con = Queue.can_push con.pkt_out CommandReply
+
 (* NB: can throw Reconnect *)
 let input con =
-	let to_read =
-		match con.partial_in with
-		| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
-		| NoHdr   (i, _)    -> i in
+	if not (can_input con) then None
+	else
+	let to_read = to_read con in
 
 	(* try to get more data from input stream *)
 	let b = Bytes.make to_read '\000' in
@@ -243,11 +277,22 @@ let input con =
 		None
 	)
 
-let newcon backend = {
+let classify t =
+	match t.Packet.ty with
+	| Op.Watchevent -> Watchevent
+	| _ -> CommandReply
+
+let newcon ~capacity backend =
+	let limit = function
+		| CommandReply -> capacity.maxoutstanding
+		| Watchevent -> capacity.maxwatchevents
+	in
+	{
 	backend = backend;
-	pkt_out = Queue.create ();
+	pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit;
 	partial_in = init_partial_in ();
 	partial_out = "";
+	capacity = capacity;
 	}
 
 let open_fd fd = newcon (Fd { fd = fd; })
diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli
index 91c682162c..71b2754ca7 100644
--- a/tools/ocaml/libs/xb/xb.mli
+++ b/tools/ocaml/libs/xb/xb.mli
@@ -66,10 +66,11 @@ type backend_mmap = {
 type backend_fd = { fd : Unix.file_descr; }
 type backend = Fd of backend_fd | Xenmmap of backend_mmap
 type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes
+type capacity = { maxoutstanding: int; maxwatchevents: int }
 type t
 val init_partial_in : unit -> partial_buf
 val reconnect : t -> unit
-val queue : t -> Packet.t -> unit
+val queue : t -> Packet.t -> unit option
 val read_fd : backend_fd -> 'a -> bytes -> int -> int
 val read_mmap : backend_mmap -> 'a -> bytes -> int -> int
 val read : t -> bytes -> int -> int
@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int
 val write : t -> string -> int -> int
 val output : t -> bool
 val input : t -> Packet.t option
-val newcon : backend -> t
-val open_fd : Unix.file_descr -> t
-val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t
+val newcon : capacity:capacity -> backend -> t
+val open_fd : Unix.file_descr -> capacity:capacity -> t
+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t
 val close : t -> unit
 val is_fd : t -> bool
 val is_mmap : t -> bool
 val output_len : t -> int
+val can_input: t -> bool
 val has_new_output : t -> bool
 val has_old_output : t -> bool
 val has_output : t -> bool
@@ -93,3 +95,4 @@ val has_partial_input : t -> bool
 val has_more_input : t -> bool
 val is_selectable : t -> bool
 val get_fd : t -> Unix.file_descr
+val debug: t -> string
diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml
index 9ff5bbd529..4e532cdaea 100644
--- a/tools/ocaml/libs/xs/queueop.ml
+++ b/tools/ocaml/libs/xs/queueop.ml
@@ -16,9 +16,10 @@
 open Xenbus
 
 let data_concat ls = (String.concat "\000" ls) ^ "\000"
+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None)
 let queue_path ty (tid: int) (path: string) con =
 	let data = data_concat [ path; ] in
-	Xb.queue con (Xb.Packet.create tid 0 ty data)
+	queue con (Xb.Packet.create tid 0 ty data)
 
 (* operations *)
 let directory tid path con = queue_path Xb.Op.Directory tid path con
@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con
 let getperms tid path con = queue_path Xb.Op.Getperms tid path con
 
 let debug commands con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands))
 
 let watch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Watch data)
 
 let unwatch path data con =
 	let data = data_concat [ path; data; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data)
 
 let transaction_start con =
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
+	queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat []))
 
 let transaction_end tid commit con =
 	let data = data_concat [ (if commit then "T" else "F"); ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data)
 
 let introduce domid mfn port con =
 	let data = data_concat [ Printf.sprintf "%u" domid;
 	                         Printf.sprintf "%nu" mfn;
 	                         string_of_int port; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data)
 
 let release domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Release data)
 
 let resume domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Resume data)
 
 let getdomainpath domid con =
 	let data = data_concat [ Printf.sprintf "%u" domid; ] in
-	Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
+	queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data)
 
 let write tid path value con =
 	let data = path ^ "\000" ^ value (* no NULL at the end *) in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Write data)
 
 let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con
 let rm tid path con = queue_path Xb.Op.Rm tid path con
 
 let setperms tid path perms con =
 	let data = data_concat [ path; perms ] in
-	Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
+	queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data)
diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml
index 451f8b38db..cbd1728060 100644
--- a/tools/ocaml/libs/xs/xsraw.ml
+++ b/tools/ocaml/libs/xs/xsraw.ml
@@ -36,8 +36,10 @@ type con = {
 let close con =
 	Xb.close con.xb
 
+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; }
+
 let open_fd fd = {
-	xb = Xb.open_fd fd;
+	xb = Xb.open_fd ~capacity fd;
 	watchevents = Queue.create ();
 }
 
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
index 3f6a8f1ad0..54f7f76516 100644
--- a/tools/ocaml/xenstored/connection.ml
+++ b/tools/ocaml/xenstored/connection.ml
@@ -20,12 +20,84 @@ open Stdext
 
 let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
 
+type 'a bounded_sender = 'a -> unit option
+(** a bounded sender accepts an ['a] item and returns:
+    None - if there is no room to accept the item
+    Some () -  if it has successfully accepted/sent the item
+ *)
+
+module BoundedPipe : sig
+	type 'a t
+
+	(** [create ~capacity ~destination] creates a bounded pipe with a
+	    local buffer holding at most [capacity] items.  Once the buffer is
+	    full it will not accept further items.  items from the pipe are
+	    flushed into [destination] as long as it accepts items.  The
+	    destination could be another pipe.
+	 *)
+	val create: capacity:int -> destination:'a bounded_sender -> 'a t
+
+	(** [is_empty t] returns whether the local buffer of [t] is empty. *)
+	val is_empty : _ t -> bool
+
+	(** [length t] the number of items in the internal buffer *)
+	val length: _ t -> int
+
+	(** [flush_pipe t] sends as many items from the local buffer as possible,
+			which could be none. *)
+	val flush_pipe: _ t -> unit
+
+	(** [push t item] tries to [flush_pipe] and then push [item]
+	    into the pipe if its [capacity] allows.
+	    Returns [None] if there is no more room
+	 *)
+	val push : 'a t -> 'a bounded_sender
+end = struct
+	(* items are enqueued in [q], and then flushed to [connect_to] *)
+	type 'a t =
+		{ q: 'a Queue.t
+		; destination: 'a bounded_sender
+		; capacity: int
+		}
+
+	let create ~capacity ~destination =
+		{ q = Queue.create (); capacity; destination }
+
+	let rec flush_pipe t =
+		if not Queue.(is_empty t.q) then
+			let item = Queue.peek t.q in
+			match t.destination item with
+			| None -> () (* no room *)
+			| Some () ->
+				(* successfully sent item to next stage *)
+				let _ = Queue.pop t.q in
+				(* continue trying to send more items *)
+				flush_pipe t
+
+	let push t item =
+		(* first try to flush as many items from this pipe as possible to make room,
+		   it is important to do this first to preserve the order of the items
+		 *)
+		flush_pipe t;
+		if Queue.length t.q < t.capacity then begin
+			(* enqueue, instead of sending directly.
+			   this ensures that [out] sees the items in the same order as we receive them
+			 *)
+			Queue.push item t.q;
+			Some (flush_pipe t)
+		end else None
+
+	let is_empty t = Queue.is_empty t.q
+	let length t = Queue.length t.q
+end
+
 type watch = {
 	con: t;
 	token: string;
 	path: string;
 	base: string;
 	is_relative: bool;
+	pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t;
 }
 
 and t = {
@@ -38,8 +110,36 @@ and t = {
 	anonid: int;
 	mutable stat_nb_ops: int;
 	mutable perm: Perms.Connection.t;
+	pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t
 }
 
+module Watch = struct
+	module T = struct
+		type t = watch
+
+		let compare w1 w2 =
+			(* cannot compare watches from different connections *)
+			assert (w1.con == w2.con);
+			match String.compare w1.token w2.token with
+			| 0 -> String.compare w1.path w2.path
+			| n -> n
+	end
+	module Set = Set.Make(T)
+
+	let flush_events t =
+		BoundedPipe.flush_pipe t.pending_watchevents;
+		not (BoundedPipe.is_empty t.pending_watchevents)
+
+	let pending_watchevents t =
+		BoundedPipe.length t.pending_watchevents
+end
+
+let source_flush_watchevents t =
+	BoundedPipe.flush_pipe t.pending_source_watchevents
+
+let source_pending_watchevents t =
+	BoundedPipe.length t.pending_source_watchevents
+
 let mark_as_bad con =
 	match con.dom with
 	|None -> ()
@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = {
 	token = token;
 	path = path;
 	base = get_path con;
-	is_relative = path.[0] <> '/' && path.[0] <> '@'
+	is_relative = path.[0] <> '/' && path.[0] <> '@';
+	pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb)
 }
 
 let get_con w = w.con
@@ -93,6 +194,9 @@ let make_perm dom =
 	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
 
 let create xbcon dom =
+	let destination (watch, pkt) =
+		BoundedPipe.push watch.pending_watchevents pkt
+	in
 	let id =
 		match dom with
 		| None -> let old = !anon_id_next in incr anon_id_next; old
@@ -109,6 +213,16 @@ let create xbcon dom =
 	anonid = id;
 	stat_nb_ops = 0;
 	perm = make_perm dom;
+
+	(* the actual capacity will be lower, this is used as an overflow
+	   buffer: anything that doesn't fit elsewhere gets put here, only
+	   limited by the amount of watches that you can generate with a
+	   single xenstore command (which is finite, although possibly very
+	   large in theory for Dom0).  Once the pipe here has any contents the
+	   domain is blocked from sending more commands until it is empty
+	   again though.
+	 *)
+	pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination
 	}
 	in
 	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
@@ -127,11 +241,17 @@ let set_target con target_domid =
 
 let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb
 
-let send_reply con tid rid ty data =
+let packet_of con tid rid ty data =
 	if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000")
+		Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000"
 	else
-		Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data)
+		Xenbus.Xb.Packet.create tid rid ty data
+
+let send_reply con tid rid ty data =
+	let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in
+	(* should never happen: we only process an input packet when there is room for an output packet *)
+	(* and the limit for replies is different from the limit for watch events *)
+	assert (result <> None)
 
 let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000")
 let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
@@ -181,11 +301,11 @@ let del_watch con path token =
 	apath, w
 
 let del_watches con =
-  Hashtbl.clear con.watches;
+  Hashtbl.reset con.watches;
   con.nb_watches <- 0
 
 let del_transactions con =
-  Hashtbl.clear con.transactions
+  Hashtbl.reset con.transactions
 
 let list_watches con =
 	let ll = Hashtbl.fold
@@ -208,21 +328,29 @@ let lookup_watch_perm path = function
 let lookup_watch_perms oldroot root path =
 	lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root)
 
-let fire_single_watch_unchecked watch =
+let fire_single_watch_unchecked source watch =
 	let data = Utils.join_by_null [watch.path; watch.token; ""] in
-	send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data
+	let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in
+
+	match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with
+	| Some () -> () (* packet queued *)
+	| None ->
+			(* a well behaved Dom0 shouldn't be able to trigger this,
+			   if it happens it is likely a Dom0 bug causing runaway memory usage
+			 *)
+			failwith "watch event overflow, cannot happen"
 
-let fire_single_watch (oldroot, root) watch =
+let fire_single_watch source (oldroot, root) watch =
 	let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in
 	let perms = lookup_watch_perms oldroot root abspath in
 	if Perms.can_fire_watch watch.con.perm perms then
-		fire_single_watch_unchecked watch
+		fire_single_watch_unchecked source watch
 	else
 		let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in
 		let con = get_domstr watch.con in
 		Logging.watch_not_fired ~con perms (Store.Path.to_string abspath)
 
-let fire_watch roots watch path =
+let fire_watch source roots watch path =
 	let new_path =
 		if watch.is_relative && path.[0] = '/'
 		then begin
@@ -232,7 +360,7 @@ let fire_watch roots watch path =
 		end else
 			path
 	in
-	fire_single_watch roots { watch with path = new_path }
+	fire_single_watch source roots { watch with path = new_path }
 
 (* Search for a valid unused transaction id. *)
 let rec valid_transaction_id con proposed_id =
@@ -280,6 +408,7 @@ let do_input con = Xenbus.Xb.input con.xb
 let has_partial_input con = Xenbus.Xb.has_partial_input con.xb
 let has_more_input con = Xenbus.Xb.has_more_input con.xb
 
+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents
 let has_output con = Xenbus.Xb.has_output con.xb
 let has_old_output con = Xenbus.Xb.has_old_output con.xb
 let has_new_output con = Xenbus.Xb.has_new_output con.xb
@@ -322,7 +451,7 @@ let prevents_live_update con = not (is_bad con)
 	&& (has_extra_connection_data con || has_transaction_data con)
 
 let has_more_work con =
-	has_more_input con || not (has_old_output con) && has_new_output con
+	(has_more_input con && can_input con) || not (has_old_output con) && has_new_output con
 
 let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
 
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
index 3c7429fe7f..7d68c583b4 100644
--- a/tools/ocaml/xenstored/connections.ml
+++ b/tools/ocaml/xenstored/connections.ml
@@ -22,22 +22,30 @@ type t = {
 	domains: (int, Connection.t) Hashtbl.t;
 	ports: (Xeneventchn.t, Connection.t) Hashtbl.t;
 	mutable watches: Connection.watch list Trie.t;
+	mutable has_pending_watchevents: Connection.Watch.Set.t
 }
 
 let create () = {
 	anonymous = Hashtbl.create 37;
 	domains = Hashtbl.create 37;
 	ports = Hashtbl.create 37;
-	watches = Trie.create ()
+	watches = Trie.create ();
+	has_pending_watchevents = Connection.Watch.Set.empty;
 }
 
+let get_capacity () =
+	(* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *)
+	{ Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents }
+
 let add_anonymous cons fd =
-	let xbcon = Xenbus.Xb.open_fd fd in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_fd fd ~capacity in
 	let con = Connection.create xbcon None in
 	Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
 
 let add_domain cons dom =
-	let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let capacity = get_capacity () in
+	let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in
 	let con = Connection.create xbcon (Some dom) in
 	Hashtbl.add cons.domains (Domain.get_id dom) con;
 	match Domain.get_port dom with
@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons =
 	Hashtbl.fold (fun _ con (ins, outs) ->
 		if (only_if con) then (
 			let fd = Connection.get_fd con in
-			(fd :: ins,  if Connection.has_output con then fd :: outs else outs)
+			let in_fds = if Connection.can_input con then fd :: ins else ins in
+			let out_fds = if Connection.has_output con then fd :: outs else outs in
+			in_fds, out_fds
 		) else (ins, outs)
 	)
 	cons.anonymous ([], [])
@@ -67,10 +77,17 @@ let del_watches_of_con con watches =
 	| [] -> None
 	| ws -> Some ws
 
+let del_watches cons con =
+	Connection.del_watches con;
+	cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w ->
+		Connection.get_con w != con
+
 let del_anonymous cons con =
 	try
 		Hashtbl.remove cons.anonymous (Connection.get_fd con);
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del anonymous %s" (Printexc.to_string exn)
@@ -85,7 +102,7 @@ let del_domain cons id =
 		    | Some p -> Hashtbl.remove cons.ports p
 		    | None -> ())
 		 | None -> ());
-		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		del_watches cons con;
 		Connection.close con
 	with exn ->
 		debug "del domain %u: %s" id (Printexc.to_string exn)
@@ -136,31 +153,33 @@ let del_watch cons con path token =
 		cons.watches <- Trie.set cons.watches key watches;
  	watch
 
-let del_watches cons con =
-	Connection.del_watches con;
-	cons.watches <- Trie.map (del_watches_of_con con) cons.watches
-
 (* path is absolute *)
-let fire_watches ?oldroot root cons path recurse =
+let fire_watches ?oldroot source root cons path recurse =
 	let key = key_of_path path in
 	let path = Store.Path.to_string path in
 	let roots = oldroot, root in
 	let fire_watch _ = function
 		| None         -> ()
-		| Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches
+		| Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches
 	in
 	let fire_rec _x = function
 		| None         -> ()
 		| Some watches ->
-			List.iter (Connection.fire_single_watch roots) watches
+			List.iter (Connection.fire_single_watch source roots) watches
 	in
 	Trie.iter_path fire_watch cons.watches key;
 	if recurse then
 		Trie.iter fire_rec (Trie.sub cons.watches key)
 
+let send_watchevents cons con =
+	cons.has_pending_watchevents <-
+		cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events;
+	Connection.source_flush_watchevents con
+
 let fire_spec_watches root cons specpath =
+	let source = find_domain cons 0 in
 	iter cons (fun con ->
-		List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath))
+		List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath))
 
 let set_target cons domain target_domain =
 	let con = find_domain cons domain in
@@ -197,6 +216,16 @@ let debug cons =
 	let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in
 	String.concat "" (domains @ anonymous)
 
+let debug_watchevents cons con =
+	(* == (physical equality)
+	   has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular
+	   comparison to fail due to having a 'functional value' which cannot be compared.
+	 *)
+	let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in
+	let pending = s |> Connection.Watch.Set.elements
+		|> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in
+	Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending
+
 let filter ~f cons =
 	let fold _ v acc = if f v then v :: acc else acc in
 	[]
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
index ba63a8147e..327b6d795e 100644
--- a/tools/ocaml/xenstored/define.ml
+++ b/tools/ocaml/xenstored/define.ml
@@ -24,6 +24,13 @@ let default_config_dir = Paths.xen_config_dir
 let maxwatch = ref (100)
 let maxtransaction = ref (10)
 let maxrequests = ref (1024)   (* maximum requests per transaction *)
+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *)
+let maxwatchevents = ref (1024)
+(*
+	maximum outstanding watch events per watch,
+	recommended >= maxoutstanding to avoid blocking backend transactions due to
+	malicious frontends
+ *)
 
 let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *)
 let conflict_burst_limit = ref 5.0
diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in
index 4ae48e42d4..9d034e744b 100644
--- a/tools/ocaml/xenstored/oxenstored.conf.in
+++ b/tools/ocaml/xenstored/oxenstored.conf.in
@@ -62,6 +62,8 @@ quota-maxwatch = 100
 quota-transaction = 10
 quota-maxrequests = 1024
 quota-path-max = 1024
+quota-maxoutstanding = 1024
+quota-maxwatchevents = 1024
 
 # Activate filed base backend
 persistent = false
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 50ef05be41..6781088387 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -57,7 +57,7 @@ let split_one_path data con =
 	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
 	| _                -> raise Invalid_Cmd_Args
 
-let process_watch t cons =
+let process_watch source t cons =
 	let oldroot = t.Transaction.oldroot in
 	let newroot = Store.get_root t.Transaction.store in
 	let ops = Transaction.get_paths t |> List.rev in
@@ -67,8 +67,9 @@ let process_watch t cons =
 		| Xenbus.Xb.Op.Rm       -> true, None, oldroot
 		| Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot
 		| _              -> raise (Failure "huh ?") in
-		Connections.fire_watches ?oldroot root cons (snd op) recurse in
-	List.iter (fun op -> do_op_watch op cons) ops
+		Connections.fire_watches ?oldroot source root cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops;
+	Connections.send_watchevents cons source
 
 let create_implicit_path t perm path =
 	let dirname = Store.Path.get_parent path in
@@ -234,6 +235,20 @@ let do_debug con t _domains cons data =
 	| "watches" :: _ ->
 		let watches = Connections.debug cons in
 		Some (watches ^ "\000")
+	| "xenbus" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s"
+			(Xenbus.Xb.debug con.xb)
+			(Connection.source_pending_watchevents con)
+			(Connection.can_input con)
+			(Connection.has_more_input con)
+			(Connection.has_old_output con)
+			(Connection.has_new_output con)
+			(Connection.has_more_work con)
+			(Connections.debug_watchevents cons con)
+		in
+		Some s
 	| "mfn" :: domid :: _ ->
 		let domid = int_of_string domid in
 		let con = Connections.find_domain cons domid in
@@ -342,7 +357,7 @@ let reply_ack fct con t doms cons data =
 	fct con t doms cons data;
 	Packet.Ack (fun () ->
 		if Transaction.get_id t = Transaction.none then
-			process_watch t cons
+			process_watch con t cons
 	)
 
 let reply_data fct con t doms cons data =
@@ -501,7 +516,7 @@ let do_watch con _t _domains cons data =
 	Packet.Ack (fun () ->
 		(* xenstore.txt says this watch is fired immediately,
 		   implying even if path doesn't exist or is unreadable *)
-		Connection.fire_single_watch_unchecked watch)
+		Connection.fire_single_watch_unchecked con watch)
 
 let do_unwatch con _t _domains cons data =
 	let (node, token) =
@@ -532,7 +547,7 @@ let do_transaction_end con t domains cons data =
 	if not success then
 		raise Transaction_again;
 	if commit then begin
-		process_watch t cons;
+		process_watch con t cons;
 		match t.Transaction.ty with
 		| Transaction.No ->
 			() (* no need to record anything *)
@@ -701,7 +716,8 @@ let process_packet ~store ~cons ~doms ~con ~req =
 let do_input store cons doms con =
 	let newpacket =
 		try
-			Connection.do_input con
+			if Connection.can_input con then Connection.do_input con
+			else None
 		with Xenbus.Xb.Reconnect ->
 			info "%s requests a reconnect" (Connection.get_domstr con);
 			History.reconnect con;
@@ -729,6 +745,7 @@ let do_input store cons doms con =
 		Connection.incr_ops con
 
 let do_output _store _cons _doms con =
+	Connection.source_flush_watchevents con;
 	if Connection.has_output con then (
 		if Connection.has_new_output con then (
 			let packet = Connection.peek_output con in
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
index 3a932f54a6..ffd43a4eee 100644
--- a/tools/ocaml/xenstored/xenstored.ml
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -103,6 +103,8 @@ let parse_config filename =
 		("quota-maxentity", Config.Set_int Quota.maxent);
 		("quota-maxsize", Config.Set_int Quota.maxsize);
 		("quota-maxrequests", Config.Set_int Define.maxrequests);
+		("quota-maxoutstanding", Config.Set_int Define.maxoutstanding);
+		("quota-maxwatchevents", Config.Set_int Define.maxwatchevents);
 		("quota-path-max", Config.Set_int Define.path_max);
 		("gc-max-overhead", Config.Set_int Define.gc_max_overhead);
 		("test-eagain", Config.Set_bool Transaction.test_eagain);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:15:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:15:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435898.689786 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCeK-0006FS-0m; Wed, 02 Nov 2022 12:15:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435898.689786; Wed, 02 Nov 2022 12:15:15 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCeJ-0006FK-UO; Wed, 02 Nov 2022 12:15:15 +0000
Received: by outflank-mailman (input) for mailman id 435898;
 Wed, 02 Nov 2022 12:15:14 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCeI-0006F7-GA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:14 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCeI-0000wQ-Fc
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:14 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCeI-0001Vo-F3
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:14 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=u6lUGuX8eVFIX678yWp5EvyMat8OxZG8Kbwr9WfqsBM=; b=GcPhj/9NUPIIORwwXdFekthki8
	A/ntOA9oNVNmCD3lQ/U4KiG43sR9N1YJo6etP35isMMT0CJ4agBOlTvVn7TPpEQZQVC5LmWpOaaFg
	1CMOLNaZ7WLldF1umOGZJ2uWGOPp+F+hIIfPFGB0wt0mAYfYta0pinQlGU87LF4YkH4w=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] SUPPORT.md: clarify support of untrusted driver domains with oxenstored
Message-Id: <E1oqCeI-0001Vo-F3@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:15:14 +0000

commit c7bc20d8d123851a468402bbfc9e3330efff21ec
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Thu Sep 29 13:07:35 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    SUPPORT.md: clarify support of untrusted driver domains with oxenstored
    
    Add a support statement for the scope of support regarding different
    Xenstore variants. Especially oxenstored does not (yet) have security
    support of untrusted driver domains, as those might drive oxenstored
    out of memory by creating lots of watch events for the guests they are
    servicing.
    
    Add a statement regarding Live Update support of oxenstored.
    
    This is part of XSA-326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: George Dunlap <george.dunlap@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
---
 SUPPORT.md | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index cf2ddfacaf..ab71464cf6 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -193,13 +193,18 @@ Support for running qemu-xen device model in a linux stubdomain.
 
     Status: Tech Preview
 
-## Liveupdate of C xenstored daemon
+## Xenstore
 
-    Status: Tech Preview
+### C xenstored daemon
 
-## Liveupdate of OCaml xenstored daemon
+    Status: Supported
+    Status, Liveupdate: Tech Preview
 
-    Status: Tech Preview
+### OCaml xenstored daemon
+
+    Status: Supported
+    Status, untrusted driver domains: Supported, not security supported
+    Status, Liveupdate: Not functional
 
 ## Toolstack/3rd party
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:15:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:15:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435899.689789 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCeU-0006IQ-2L; Wed, 02 Nov 2022 12:15:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435899.689789; Wed, 02 Nov 2022 12:15:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCeT-0006IJ-Vz; Wed, 02 Nov 2022 12:15:25 +0000
Received: by outflank-mailman (input) for mailman id 435899;
 Wed, 02 Nov 2022 12:15:24 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCeS-0006I5-JU
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:24 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCeS-0000wb-Ir
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:24 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCeS-0001WK-I5
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:24 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=dS5dKOZBaD8ZQNerVddmoIZgB/HAH4CzUBrScQVswiI=; b=n8ujw31TD3OPhAZObggzwLftV3
	3q6+kzUEbdLjWXbnKTY/QLrgIaZ9RniY8uW7NW2wkMGcHQ3zmqIjgSIQfKaJqAN/yzBykg4pL64RT
	vDZtWckrSslMSXibkge6K2P/yTFzVZOMUOr+j3xQT9EhX33STDie8IJeS5pdEk53jvbI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: don't use conn->in as context for temporary allocations
Message-Id: <E1oqCeS-0001WK-I5@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:15:24 +0000

commit 2a587de219cc0765330fbf9fac6827bfaf29e29b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: don't use conn->in as context for temporary allocations
    
    Using the struct buffered data pointer of the current processed request
    for temporary data allocations has a major drawback: the used area (and
    with that the temporary data) is freed only after the response of the
    request has been written to the ring page or has been read via the
    socket. This can happen much later in case a guest isn't reading its
    responses fast enough.
    
    As the temporary data can be safely freed after creating the response,
    add a temporary context for that purpose and use that for allocating
    the temporary memory, as it was already the case before commit
    cc0612464896 ("xenstore: add small default data buffer to internal
    struct").
    
    Some sub-functions need to gain the "const" attribute for the talloc
    context.
    
    This is XSA-416 / CVE-2022-42319.
    
    Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_control.c     | 31 +++++++-------
 tools/xenstore/xenstored_control.h     |  3 +-
 tools/xenstore/xenstored_core.c        | 76 +++++++++++++++++++++-------------
 tools/xenstore/xenstored_domain.c      | 29 +++++++------
 tools/xenstore/xenstored_domain.h      | 21 ++++++----
 tools/xenstore/xenstored_transaction.c | 14 ++++---
 tools/xenstore/xenstored_transaction.h |  6 ++-
 tools/xenstore/xenstored_watch.c       |  9 ++--
 tools/xenstore/xenstored_watch.h       |  6 ++-
 9 files changed, 118 insertions(+), 77 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index 264bb39d7b..d1aaa00bf4 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -155,7 +155,7 @@ bool lu_is_pending(void)
 
 struct cmd_s {
 	char *cmd;
-	int (*func)(void *, struct connection *, char **, int);
+	int (*func)(const void *, struct connection *, char **, int);
 	char *pars;
 	/*
 	 * max_pars can be used to limit the size of the parameter vector,
@@ -167,7 +167,7 @@ struct cmd_s {
 	unsigned int max_pars;
 };
 
-static int do_control_check(void *ctx, struct connection *conn,
+static int do_control_check(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num)
@@ -179,7 +179,7 @@ static int do_control_check(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_log(void *ctx, struct connection *conn,
+static int do_control_log(const void *ctx, struct connection *conn,
 			  char **vec, int num)
 {
 	if (num != 1)
@@ -281,7 +281,7 @@ static int quota_get(const void *ctx, struct connection *conn,
 	return domain_get_quota(ctx, conn, atoi(vec[0]));
 }
 
-static int do_control_quota(void *ctx, struct connection *conn,
+static int do_control_quota(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num == 0)
@@ -293,7 +293,7 @@ static int do_control_quota(void *ctx, struct connection *conn,
 	return quota_get(ctx, conn, vec, num);
 }
 
-static int do_control_quota_s(void *ctx, struct connection *conn,
+static int do_control_quota_s(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num == 0)
@@ -306,7 +306,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn,
 }
 
 #ifdef __MINIOS__
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	if (num)
@@ -318,7 +318,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 	return 0;
 }
 #else
-static int do_control_logfile(void *ctx, struct connection *conn,
+static int do_control_logfile(const void *ctx, struct connection *conn,
 			      char **vec, int num)
 {
 	if (num != 1)
@@ -333,7 +333,7 @@ static int do_control_logfile(void *ctx, struct connection *conn,
 	return 0;
 }
 
-static int do_control_memreport(void *ctx, struct connection *conn,
+static int do_control_memreport(const void *ctx, struct connection *conn,
 				char **vec, int num)
 {
 	FILE *fp;
@@ -373,7 +373,7 @@ static int do_control_memreport(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_print(void *ctx, struct connection *conn,
+static int do_control_print(const void *ctx, struct connection *conn,
 			    char **vec, int num)
 {
 	if (num != 1)
@@ -875,7 +875,7 @@ static const char *lu_start(const void *ctx, struct connection *conn,
 	return NULL;
 }
 
-static int do_control_lu(void *ctx, struct connection *conn,
+static int do_control_lu(const void *ctx, struct connection *conn,
 			 char **vec, int num)
 {
 	const char *ret = NULL;
@@ -922,7 +922,7 @@ static int do_control_lu(void *ctx, struct connection *conn,
 }
 #endif
 
-static int do_control_help(void *, struct connection *, char **, int);
+static int do_control_help(const void *, struct connection *, char **, int);
 
 static struct cmd_s cmds[] = {
 	{ "check", do_control_check, "" },
@@ -961,7 +961,7 @@ static struct cmd_s cmds[] = {
 	{ "help", do_control_help, "" },
 };
 
-static int do_control_help(void *ctx, struct connection *conn,
+static int do_control_help(const void *ctx, struct connection *conn,
 			   char **vec, int num)
 {
 	int cmd;
@@ -984,7 +984,8 @@ static int do_control_help(void *ctx, struct connection *conn,
 	return 0;
 }
 
-int do_control(struct connection *conn, struct buffered_data *in)
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	unsigned int cmd, num, off;
 	char **vec = NULL;
@@ -1004,11 +1005,11 @@ int do_control(struct connection *conn, struct buffered_data *in)
 	num = xs_count_strings(in->buffer, in->used);
 	if (cmds[cmd].max_pars)
 		num = min(num, cmds[cmd].max_pars);
-	vec = talloc_array(in, char *, num);
+	vec = talloc_array(ctx, char *, num);
 	if (!vec)
 		return ENOMEM;
 	if (get_strings(in, vec, num) < num)
 		return EIO;
 
-	return cmds[cmd].func(in, conn, vec + 1, num - 1);
+	return cmds[cmd].func(ctx, conn, vec + 1, num - 1);
 }
diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h
index 98b6fbcea2..a8cb76559b 100644
--- a/tools/xenstore/xenstored_control.h
+++ b/tools/xenstore/xenstored_control.h
@@ -16,7 +16,8 @@
     along with this program; If not, see <http://www.gnu.org/licenses/>.
 */
 
-int do_control(struct connection *conn, struct buffered_data *in);
+int do_control(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 void lu_read_state(void);
 
 struct connection *lu_get_connection(void);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f7f1e00c71..66bbeaf6bf 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1244,11 +1244,13 @@ static struct node *get_node_canonicalized(struct connection *conn,
 	return get_node(conn, ctx, *canonical_name, perm);
 }
 
-static int send_directory(struct connection *conn, struct buffered_data *in)
+static int send_directory(const void *ctx, struct connection *conn,
+			  struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1257,7 +1259,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int send_directory_part(struct connection *conn,
+static int send_directory_part(const void *ctx, struct connection *conn,
 			       struct buffered_data *in)
 {
 	unsigned int off, len, maxlen, genlen;
@@ -1269,7 +1271,8 @@ static int send_directory_part(struct connection *conn,
 		return EINVAL;
 
 	/* First arg is node name. */
-	node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, in->buffer, NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1296,7 +1299,7 @@ static int send_directory_part(struct connection *conn,
 			break;
 	}
 
-	data = talloc_array(in, char, genlen + len + 1);
+	data = talloc_array(ctx, char, genlen + len + 1);
 	if (!data)
 		return ENOMEM;
 
@@ -1312,11 +1315,13 @@ static int send_directory_part(struct connection *conn,
 	return 0;
 }
 
-static int do_read(struct connection *conn, struct buffered_data *in)
+static int do_read(const void *ctx, struct connection *conn,
+		   struct buffered_data *in)
 {
 	struct node *node;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1506,7 +1511,8 @@ err:
 }
 
 /* path, data... */
-static int do_write(struct connection *conn, struct buffered_data *in)
+static int do_write(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	unsigned int offset, datalen;
 	struct node *node;
@@ -1520,12 +1526,12 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 	offset = strlen(vec[0]) + 1;
 	datalen = in->used - offset;
 
-	node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE);
+	node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE);
 	if (!node) {
 		/* No permissions, invalid input? */
 		if (errno != ENOENT)
 			return errno;
-		node = create_node(conn, in, name, in->buffer + offset,
+		node = create_node(conn, ctx, name, in->buffer + offset,
 				   datalen);
 		if (!node)
 			return errno;
@@ -1536,18 +1542,19 @@ static int do_write(struct connection *conn, struct buffered_data *in)
 			return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, NULL);
+	fire_watches(conn, ctx, name, node, false, NULL);
 	send_ack(conn, XS_WRITE);
 
 	return 0;
 }
 
-static int do_mkdir(struct connection *conn, struct buffered_data *in)
+static int do_mkdir(const void *ctx, struct connection *conn,
+		    struct buffered_data *in)
 {
 	struct node *node;
 	char *name;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 
 	/* If it already exists, fine. */
@@ -1557,10 +1564,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in)
 			return errno;
 		if (!name)
 			return ENOMEM;
-		node = create_node(conn, in, name, NULL, 0);
+		node = create_node(conn, ctx, name, NULL, 0);
 		if (!node)
 			return errno;
-		fire_watches(conn, in, name, node, false, NULL);
+		fire_watches(conn, ctx, name, node, false, NULL);
 	}
 	send_ack(conn, XS_MKDIR);
 
@@ -1658,24 +1665,25 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 }
 
 
-static int do_rm(struct connection *conn, struct buffered_data *in)
+static int do_rm(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct node *node;
 	int ret;
 	char *name;
 	char *parentname;
 
-	node = get_node_canonicalized(conn, in, onearg(in), &name,
+	node = get_node_canonicalized(conn, ctx, onearg(in), &name,
 				      XS_PERM_WRITE);
 	if (!node) {
 		/* Didn't exist already?  Fine, if parent exists. */
 		if (errno == ENOENT) {
 			if (!name)
 				return ENOMEM;
-			parentname = get_parent(in, name);
+			parentname = get_parent(ctx, name);
 			if (!parentname)
 				return errno;
-			node = read_node(conn, in, parentname);
+			node = read_node(conn, ctx, parentname);
 			if (node) {
 				send_ack(conn, XS_RM);
 				return 0;
@@ -1690,7 +1698,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, in, node, name);
+	ret = _rm(conn, ctx, node, name);
 	if (ret)
 		return ret;
 
@@ -1700,13 +1708,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in)
 }
 
 
-static int do_get_perms(struct connection *conn, struct buffered_data *in)
+static int do_get_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node *node;
 	char *strings;
 	unsigned int len;
 
-	node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ);
+	node = get_node_canonicalized(conn, ctx, onearg(in), NULL,
+				      XS_PERM_READ);
 	if (!node)
 		return errno;
 
@@ -1719,7 +1729,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-static int do_set_perms(struct connection *conn, struct buffered_data *in)
+static int do_set_perms(const void *ctx, struct connection *conn,
+			struct buffered_data *in)
 {
 	struct node_perms perms, old_perms;
 	char *name, *permstr;
@@ -1736,7 +1747,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 	permstr = in->buffer + strlen(in->buffer) + 1;
 
-	perms.p = talloc_array(in, struct xs_permissions, perms.num);
+	perms.p = talloc_array(ctx, struct xs_permissions, perms.num);
 	if (!perms.p)
 		return ENOMEM;
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
@@ -1751,7 +1762,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 	}
 
 	/* We must own node to do this (tools can do this too). */
-	node = get_node_canonicalized(conn, in, in->buffer, &name,
+	node = get_node_canonicalized(conn, ctx, in->buffer, &name,
 				      XS_PERM_WRITE | XS_PERM_OWNER);
 	if (!node)
 		return errno;
@@ -1786,7 +1797,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 		return errno;
 	}
 
-	fire_watches(conn, in, name, node, false, &old_perms);
+	fire_watches(conn, ctx, name, node, false, &old_perms);
 	send_ack(conn, XS_SET_PERMS);
 
 	return 0;
@@ -1794,7 +1805,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in)
 
 static struct {
 	const char *str;
-	int (*func)(struct connection *conn, struct buffered_data *in);
+	int (*func)(const void *ctx, struct connection *conn,
+		    struct buffered_data *in);
 	unsigned int flags;
 #define XS_FLAG_NOTID		(1U << 0)	/* Ignore transaction id. */
 #define XS_FLAG_PRIV		(1U << 1)	/* Privileged domain only. */
@@ -1847,6 +1859,7 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 	struct transaction *trans;
 	enum xsd_sockmsg_type type = in->hdr.msg.type;
 	int ret;
+	void *ctx;
 
 	/* At least send_error() and send_reply() expects conn->in == in */
 	assert(conn->in == in);
@@ -1871,10 +1884,17 @@ static void process_message(struct connection *conn, struct buffered_data *in)
 		return;
 	}
 
+	ctx = talloc_new(NULL);
+	if (!ctx) {
+		send_error(conn, ENOMEM);
+		return;
+	}
+
 	assert(conn->transaction == NULL);
 	conn->transaction = trans;
 
-	ret = wire_funcs[type].func(conn, in);
+	ret = wire_funcs[type].func(ctx, conn, in);
+	talloc_free(ctx);
 	if (ret)
 		send_error(conn, ret);
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 983b348ee5..b9ff4ded83 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -330,7 +330,7 @@ bool domain_is_unprivileged(struct connection *conn)
 	       domid_is_unprivileged(conn->domain->domid);
 }
 
-static char *talloc_domain_path(void *context, unsigned int domid)
+static char *talloc_domain_path(const void *context, unsigned int domid)
 {
 	return talloc_asprintf(context, "/local/domain/%u", domid);
 }
@@ -566,7 +566,8 @@ static struct domain *introduce_domain(const void *ctx,
 }
 
 /* domid, gfn, evtchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in)
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in)
 {
 	struct domain *domain;
 	char *vec[3];
@@ -584,7 +585,7 @@ int do_introduce(struct connection *conn, struct buffered_data *in)
 	if (port <= 0)
 		return EINVAL;
 
-	domain = introduce_domain(in, domid, port, false);
+	domain = introduce_domain(ctx, domid, port, false);
 	if (!domain)
 		return errno;
 
@@ -607,7 +608,8 @@ static struct domain *find_connected_domain(unsigned int domid)
 	return domain;
 }
 
-int do_set_target(struct connection *conn, struct buffered_data *in)
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in)
 {
 	char *vec[2];
 	unsigned int domid, tdomid;
@@ -651,7 +653,8 @@ static struct domain *onearg_domain(struct connection *conn,
 }
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in)
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -666,7 +669,8 @@ int do_release(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_resume(struct connection *conn, struct buffered_data *in)
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in)
 {
 	struct domain *domain;
 
@@ -681,7 +685,8 @@ int do_resume(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_get_domain_path(struct connection *conn, struct buffered_data *in)
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	char *path;
 	const char *domid_str = onearg(in);
@@ -689,18 +694,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in)
 	if (!domid_str)
 		return EINVAL;
 
-	path = talloc_domain_path(conn, atoi(domid_str));
+	path = talloc_domain_path(ctx, atoi(domid_str));
 	if (!path)
 		return errno;
 
 	send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
 
-	talloc_free(path);
-
 	return 0;
 }
 
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in)
 {
 	int result;
 	unsigned int domid;
@@ -721,7 +725,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in)
 }
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in)
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in)
 {
 	conn_delete_all_watches(conn);
 	conn_delete_all_transactions(conn);
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 5b86a92e1b..2094421909 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -24,25 +24,32 @@ void handle_event(void);
 void check_domains(void);
 
 /* domid, mfn, eventchn, path */
-int do_introduce(struct connection *conn, struct buffered_data *in);
+int do_introduce(const void *ctx, struct connection *conn,
+		 struct buffered_data *in);
 
 /* domid */
-int do_is_domain_introduced(struct connection *conn, struct buffered_data *in);
+int do_is_domain_introduced(const void *ctx, struct connection *conn,
+			    struct buffered_data *in);
 
 /* domid */
-int do_release(struct connection *conn, struct buffered_data *in);
+int do_release(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* domid */
-int do_resume(struct connection *conn, struct buffered_data *in);
+int do_resume(const void *ctx, struct connection *conn,
+	      struct buffered_data *in);
 
 /* domid, target */
-int do_set_target(struct connection *conn, struct buffered_data *in);
+int do_set_target(const void *ctx, struct connection *conn,
+		  struct buffered_data *in);
 
 /* domid */
-int do_get_domain_path(struct connection *conn, struct buffered_data *in);
+int do_get_domain_path(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 /* Allow guest to reset all watches */
-int do_reset_watches(struct connection *conn, struct buffered_data *in);
+int do_reset_watches(const void *ctx, struct connection *conn,
+		     struct buffered_data *in);
 
 void domain_init(int evtfd);
 void dom0_init(void);
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 28774813de..3e3eb47326 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -481,7 +481,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id)
 	return ERR_PTR(-ENOENT);
 }
 
-int do_transaction_start(struct connection *conn, struct buffered_data *in)
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *in)
 {
 	struct transaction *trans, *exists;
 	char id_str[20];
@@ -494,8 +495,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in)
 	    conn->transaction_started > quota_max_transaction)
 		return ENOSPC;
 
-	/* Attach transaction to input for autofree until it's complete */
-	trans = talloc_zero(in, struct transaction);
+	/* Attach transaction to ctx for autofree until it's complete */
+	trans = talloc_zero(ctx, struct transaction);
 	if (!trans)
 		return ENOMEM;
 
@@ -544,7 +545,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update)
 	return 0;
 }
 
-int do_transaction_end(struct connection *conn, struct buffered_data *in)
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in)
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
@@ -562,8 +564,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in)
 	if (!conn->transaction_started)
 		conn->ta_start_time = 0;
 
-	/* Attach transaction to in for auto-cleanup */
-	talloc_steal(in, trans);
+	/* Attach transaction to ctx for auto-cleanup */
+	talloc_steal(ctx, trans);
 
 	if (streq(arg, "T")) {
 		if (trans->fail)
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index e3cbd6b230..39d7f81c51 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -29,8 +29,10 @@ struct transaction;
 
 extern uint64_t generation;
 
-int do_transaction_start(struct connection *conn, struct buffered_data *node);
-int do_transaction_end(struct connection *conn, struct buffered_data *in);
+int do_transaction_start(const void *ctx, struct connection *conn,
+			 struct buffered_data *node);
+int do_transaction_end(const void *ctx, struct connection *conn,
+		       struct buffered_data *in);
 
 struct transaction *transaction_lookup(struct connection *conn, uint32_t id);
 
diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c
index 85362bcce3..316c08b7f7 100644
--- a/tools/xenstore/xenstored_watch.c
+++ b/tools/xenstore/xenstored_watch.c
@@ -243,7 +243,7 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token,
 	return NULL;
 }
 
-int do_watch(struct connection *conn, struct buffered_data *in)
+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
 {
 	struct watch *watch;
 	char *vec[2];
@@ -252,7 +252,7 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	errno = check_watch_path(conn, in, &(vec[0]), &relative);
+	errno = check_watch_path(conn, ctx, &(vec[0]), &relative);
 	if (errno)
 		return errno;
 
@@ -283,7 +283,8 @@ int do_watch(struct connection *conn, struct buffered_data *in)
 	return 0;
 }
 
-int do_unwatch(struct connection *conn, struct buffered_data *in)
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in)
 {
 	struct watch *watch;
 	char *node, *vec[2];
@@ -291,7 +292,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in)
 	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
 		return EINVAL;
 
-	node = canonicalize(conn, in, vec[0]);
+	node = canonicalize(conn, ctx, vec[0]);
 	if (!node)
 		return ENOMEM;
 	list_for_each_entry(watch, &conn->watches, list) {
diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h
index 0e693f0839..091890edca 100644
--- a/tools/xenstore/xenstored_watch.h
+++ b/tools/xenstore/xenstored_watch.h
@@ -21,8 +21,10 @@
 
 #include "xenstored_core.h"
 
-int do_watch(struct connection *conn, struct buffered_data *in);
-int do_unwatch(struct connection *conn, struct buffered_data *in);
+int do_watch(const void *ctx, struct connection *conn,
+	     struct buffered_data *in);
+int do_unwatch(const void *ctx, struct connection *conn,
+	       struct buffered_data *in);
 
 /* Fire all watches: !exact means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const void *tmp, const char *name,
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:15:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:15:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435900.689794 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCee-0006Lc-6L; Wed, 02 Nov 2022 12:15:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435900.689794; Wed, 02 Nov 2022 12:15:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCee-0006LU-3W; Wed, 02 Nov 2022 12:15:36 +0000
Received: by outflank-mailman (input) for mailman id 435900;
 Wed, 02 Nov 2022 12:15:34 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCec-0006LH-Mh
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:34 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCec-0000wl-M0
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:34 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCec-0001Wr-LJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:34 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=i0SbotYMr+ZLDF99Dsqa9Kq5KS1xy+G1PZC7Hwwp/Z4=; b=xGfla5TbHy8+93+SIRJw/gR90w
	FghPT0ZKOdJPehqkPSHHGeiFG7gnJVWXssawmKFtbfbgF+x/553Hv8PrlW7Wj1Kb3JaV0t+lBJPF4
	6Nh1JEkXZnji66eKTcYFtTKXiBPGL9dJqoM+GI27IkKCO6g1gOM3iId+PdNzhyZZQ0gs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: fix checking node permissions
Message-Id: <E1oqCec-0001Wr-LJ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:15:34 +0000

commit ab128218225d3542596ca3a02aee80d55494bef8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:10 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: fix checking node permissions
    
    Today chk_domain_generation() is being used to check whether a node
    permission entry is still valid or whether it is referring to a domain
    no longer existing. This is done by comparing the node's and the
    domain's generation count.
    
    In case no struct domain is existing for a checked domain, but the
    domain itself is valid, chk_domain_generation() assumes it is being
    called due to the first node created for a new domain and it will
    return success.
    
    This might be wrong in case the checked permission is related to an
    old domain, which has just been replaced with a new domain using the
    same domid.
    
    Fix that by letting chk_domain_generation() fail in case a struct
    domain isn't found. In order to cover the case of the first node for
    a new domain try to allocate the needed struct domain explicitly when
    processing the related SET_PERMS command. In case a referenced domain
    isn't existing, flag the related permission to be ignored right away.
    
    This is XSA-417 / CVE-2022-42320.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   |  5 +++++
 tools/xenstore/xenstored_domain.c | 37 +++++++++++++++++++++++++------------
 tools/xenstore/xenstored_domain.h |  1 +
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 66bbeaf6bf..a0c176fa20 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1753,6 +1753,11 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	if (!xs_strings_to_perms(perms.p, perms.num, permstr))
 		return errno;
 
+	if (domain_alloc_permrefs(&perms) < 0)
+		return ENOMEM;
+	if (perms.p[0].perms & XS_PERM_IGNORE)
+		return ENOENT;
+
 	/* First arg is node name. */
 	if (strstarts(in->buffer, "@")) {
 		if (set_perms_special(conn, in->buffer, &perms))
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index b9ff4ded83..98b401fdec 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -907,7 +907,6 @@ int domain_entry_inc(struct connection *conn, struct node *node)
  * count (used for testing whether a node permission is older than a domain).
  *
  * Return values:
- * -1: error
  *  0: domain has higher generation count (it is younger than a node with the
  *     given count), or domain isn't existing any longer
  *  1: domain is older than the node
@@ -915,20 +914,38 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 static int chk_domain_generation(unsigned int domid, uint64_t gen)
 {
 	struct domain *d;
-	xc_dominfo_t dominfo;
 
 	if (!xc_handle && domid == 0)
 		return 1;
 
 	d = find_domain_struct(domid);
-	if (d)
-		return (d->generation <= gen) ? 1 : 0;
 
-	if (!get_domain_info(domid, &dominfo))
-		return 0;
+	return (d && d->generation <= gen) ? 1 : 0;
+}
 
-	d = alloc_domain(NULL, domid);
-	return d ? 1 : -1;
+/*
+ * Allocate all missing struct domain referenced by a permission set.
+ * Any permission entries for not existing domains will be marked to be
+ * ignored.
+ */
+int domain_alloc_permrefs(struct node_perms *perms)
+{
+	unsigned int i, domid;
+	struct domain *d;
+	xc_dominfo_t dominfo;
+
+	for (i = 0; i < perms->num; i++) {
+		domid = perms->p[i].id;
+		d = find_domain_struct(domid);
+		if (!d) {
+			if (!get_domain_info(domid, &dominfo))
+				perms->p[i].perms |= XS_PERM_IGNORE;
+			else if (!alloc_domain(NULL, domid))
+				return ENOMEM;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -941,8 +958,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 	int ret;
 
 	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-	if (ret < 0)
-		return errno;
 
 	/* If the owner doesn't exist any longer give it to priv domain. */
 	if (!ret) {
@@ -959,8 +974,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node)
 			continue;
 		ret = chk_domain_generation(node->perms.p[i].id,
 					    node->generation);
-		if (ret < 0)
-			return errno;
 		if (!ret)
 			node->perms.p[i].perms |= XS_PERM_IGNORE;
 	}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 2094421909..7fe0a21d9e 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -63,6 +63,7 @@ bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
 int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
 int domain_entry_inc(struct connection *conn, struct node *);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:15:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:15:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435901.689797 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCeo-0006OZ-7k; Wed, 02 Nov 2022 12:15:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435901.689797; Wed, 02 Nov 2022 12:15:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCeo-0006OR-56; Wed, 02 Nov 2022 12:15:46 +0000
Received: by outflank-mailman (input) for mailman id 435901;
 Wed, 02 Nov 2022 12:15:44 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCem-0006OE-QF
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:44 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCem-0000wv-Or
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:44 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCem-0001XG-OH
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:44 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=hi3JCtg8Di0IHe8TDMdaRfi1YXEOJKSDEqz1x5CdEAk=; b=UEpsnIl60TbouYn0/Cd0rvkOxx
	uQptDF4PwQfSvLNFPfkPwH6WZESztgSWcy3T9fGQ5GAi0TRilo2vH0XcyGIryxZjLUQL6fcEGZlb4
	I6NRt73R13ZrzxhWaR+vva2i9I+OX3HgiuJDwOrMdy1gjhsWpfLMQ6FLsVDYM6v0D5/0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: remove recursion from construct_node()
Message-Id: <E1oqCem-0001XG-OH@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:15:44 +0000

commit da8ee25d02a5447ba39a9800ee2a710ae1f54222
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: remove recursion from construct_node()
    
    In order to reduce stack usage due to recursion, switch
    construct_node() to use a loop instead.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 86 ++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 31 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index a0c176fa20..cb52f68d4d 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1373,45 +1373,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name)
 static struct node *construct_node(struct connection *conn, const void *ctx,
 				   const char *name)
 {
-	struct node *parent, *node;
-	char *parentname = get_parent(ctx, name);
+	const char **names = NULL;
+	unsigned int levels = 0;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+	const char *parentname = talloc_strdup(ctx, name);
 
 	if (!parentname)
 		return NULL;
 
-	/* If parent doesn't exist, create it. */
-	parent = read_node(conn, parentname, parentname);
-	if (!parent && errno == ENOENT)
-		parent = construct_node(conn, ctx, parentname);
-	if (!parent)
-		return NULL;
+	/* Walk the path up until an existing node is found. */
+	while (!parent) {
+		names = talloc_realloc(ctx, names, const char *, levels + 1);
+		if (!names)
+			goto nomem;
 
-	/* Add child to parent. */
-	if (add_child(ctx, parent, name))
-		goto nomem;
+		/*
+		 * names[0] is the name of the node to construct initially,
+		 * names[1] is its parent, and so on.
+		 */
+		names[levels] = parentname;
+		parentname = get_parent(ctx, parentname);
+		if (!parentname)
+			return NULL;
 
-	/* Allocate node */
-	node = talloc(ctx, struct node);
-	if (!node)
-		goto nomem;
-	node->name = talloc_strdup(node, name);
-	if (!node->name)
-		goto nomem;
+		/* Try to read parent node until we found an existing one. */
+		parent = read_node(conn, ctx, parentname);
+		if (!parent && (errno != ENOENT || !strcmp(parentname, "/")))
+			return NULL;
 
-	/* Inherit permissions, except unprivileged domains own what they create */
-	node->perms.num = parent->perms.num;
-	node->perms.p = talloc_memdup(node, parent->perms.p,
-				      node->perms.num * sizeof(*node->perms.p));
-	if (!node->perms.p)
-		goto nomem;
-	if (domain_is_unprivileged(conn))
-		node->perms.p[0].id = conn->id;
+		levels++;
+	}
+
+	/* Walk the path down again constructing the missing nodes. */
+	for (; levels > 0; levels--) {
+		/* Add child to parent. */
+		if (add_child(ctx, parent, names[levels - 1]))
+			goto nomem;
+
+		/* Allocate node */
+		node = talloc(ctx, struct node);
+		if (!node)
+			goto nomem;
+		node->name = talloc_steal(node, names[levels - 1]);
+
+		/* Inherit permissions, unpriv domains own what they create. */
+		node->perms.num = parent->perms.num;
+		node->perms.p = talloc_memdup(node, parent->perms.p,
+					      node->perms.num *
+					      sizeof(*node->perms.p));
+		if (!node->perms.p)
+			goto nomem;
+		if (domain_is_unprivileged(conn))
+			node->perms.p[0].id = conn->id;
+
+		/* No children, no data */
+		node->children = node->data = NULL;
+		node->childlen = node->datalen = 0;
+		node->acc.memory = 0;
+		node->parent = parent;
+
+		parent = node;
+	}
 
-	/* No children, no data */
-	node->children = node->data = NULL;
-	node->childlen = node->datalen = 0;
-	node->acc.memory = 0;
-	node->parent = parent;
 	return node;
 
 nomem:
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:15:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:15:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435902.689802 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCey-0006R8-9Q; Wed, 02 Nov 2022 12:15:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435902.689802; Wed, 02 Nov 2022 12:15:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCey-0006R0-6d; Wed, 02 Nov 2022 12:15:56 +0000
Received: by outflank-mailman (input) for mailman id 435902;
 Wed, 02 Nov 2022 12:15:54 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCew-0006Qj-SI
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:54 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCew-0000xO-Rj
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:54 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCew-0001Xm-R9
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:15:54 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=62JN3LhKOhdbDm69WeoSrU4UFx4Q63D3r4Kktrq3mwY=; b=q1E8fmy4OM4Tht2ry/rFqKvOLq
	lrRurmTSKBTCv7bw03R9deHV35glLAzDnlZusZypwtTFjVEf61L8nc8v2m3VKr8yRTD7ekWlsJNnH
	L6vJyNWfJDKe9tmFw9zId6dx4WYsEb5P834SXwS1c9iPnDjJ0/S4rh/HDRcIi+YtQ9mA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: don't let remove_child_entry() call corrupt()
Message-Id: <E1oqCew-0001Xm-R9@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:15:54 +0000

commit 0c00c51f3bc8206c7f9cf87d014650157bee2bf4
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: don't let remove_child_entry() call corrupt()
    
    In case of write_node() returning an error, remove_child_entry() will
    call corrupt() today. This could result in an endless recursion, as
    remove_child_entry() is called by corrupt(), too:
    
    corrupt()
      check_store()
        check_store_()
          remove_child_entry()
    
    Fix that by letting remove_child_entry() return an error instead and
    let the caller decide what to do.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index cb52f68d4d..5642917e67 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1604,15 +1604,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total)
 	memmove(mem + off, mem + off + len, total - off - len);
 }
 
-static void remove_child_entry(struct connection *conn, struct node *node,
-			       size_t offset)
+static int remove_child_entry(struct connection *conn, struct node *node,
+			      size_t offset)
 {
 	size_t childlen = strlen(node->children + offset);
 
 	memdel(node->children, offset, childlen + 1, node->childlen);
 	node->childlen -= childlen + 1;
-	if (write_node(conn, node, true))
-		corrupt(conn, "Can't update parent node '%s'", node->name);
+
+	return write_node(conn, node, true);
 }
 
 static void delete_child(struct connection *conn,
@@ -1622,7 +1622,9 @@ static void delete_child(struct connection *conn,
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			remove_child_entry(conn, node, i);
+			if (remove_child_entry(conn, node, i))
+				corrupt(conn, "Can't update parent node '%s'",
+					node->name);
 			return;
 		}
 	}
@@ -2304,6 +2306,17 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
+static int rm_child_entry(struct node *node, size_t off, size_t len)
+{
+	if (!recovery)
+		return off;
+
+	if (remove_child_entry(NULL, node, off))
+		log("check_store: child entry could not be removed from '%s'",
+		    node->name);
+
+	return off - len - 1;
+}
 
 /**
  * A node has a children field that names the children of the node, separated
@@ -2356,12 +2369,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				if (hashtable_search(children, childname)) {
 					log("check_store: '%s' is duplicated!",
 					    childname);
-
-					if (recovery) {
-						remove_child_entry(NULL, node,
-								   i);
-						i -= childlen + 1;
-					}
+					i = rm_child_entry(node, i, childlen);
 				}
 				else {
 					if (!remember_string(children,
@@ -2378,11 +2386,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
-
-				if (recovery) {
-					remove_child_entry(NULL, node, i);
-					i -= childlen + 1;
-				}
+				i = rm_child_entry(node, i, childlen);
 			} else {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:16:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:16:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435903.689806 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCf8-0006UB-B0; Wed, 02 Nov 2022 12:16:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435903.689806; Wed, 02 Nov 2022 12:16:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCf8-0006U3-8B; Wed, 02 Nov 2022 12:16:06 +0000
Received: by outflank-mailman (input) for mailman id 435903;
 Wed, 02 Nov 2022 12:16:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCf6-0006Tb-VE
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:04 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCf6-0000yc-Ub
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:04 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCf6-0001YS-U4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:04 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0SgxWoBvgmn99/xeoSic25Fi7VLs7WhiVkHWFswnLNY=; b=jYtRqFCAfTPMP2BZGpNS9wikdg
	0Lzw58NFNSrPlX9j5wo0eOoTGnR6kZVH2r4rKDUMj9eiDEW1Nj4WASoNleffI2k7YTISGatvWmuzZ
	ROMN7EcQacwG6Fs9jHEwnEqXSNLD8M90I6zZHMMYU3EbMsitlmGpFvKtKR+v277dld6E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: add generic treewalk function
Message-Id: <E1oqCf6-0001YS-U4@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:16:04 +0000

commit 0d7c5d19bc27492360196e7dad2b227908564fff
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:11 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: add generic treewalk function
    
    Add a generic function to walk the complete node tree. It will start
    at "/" and descend recursively into each child, calling a function
    specified by the caller. Depending on the return value of the user
    specified function the walk will be aborted, continued, or the current
    child will be skipped by not descending into its children.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 143 ++++++++++++++++++++++++++++++++++++----
 tools/xenstore/xenstored_core.h |  40 +++++++++++
 2 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 5642917e67..f78faf0c3e 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1834,6 +1834,135 @@ static int do_set_perms(const void *ctx, struct connection *conn,
 	return 0;
 }
 
+static char *child_name(const void *ctx, const char *s1, const char *s2)
+{
+	if (strcmp(s1, "/"))
+		return talloc_asprintf(ctx, "%s/%s", s1, s2);
+	return talloc_asprintf(ctx, "/%s", s2);
+}
+
+static int rm_from_parent(struct connection *conn, struct node *parent,
+			  const char *name)
+{
+	size_t off;
+
+	if (!parent)
+		return WALK_TREE_ERROR_STOP;
+
+	for (off = parent->childoff - 1; off && parent->children[off - 1];
+	     off--);
+	if (remove_child_entry(conn, parent, off)) {
+		log("treewalk: child entry could not be removed from '%s'",
+		    parent->name);
+		return WALK_TREE_ERROR_STOP;
+	}
+	parent->childoff = off;
+
+	return WALK_TREE_OK;
+}
+
+static int walk_call_func(const void *ctx, struct connection *conn,
+			  struct node *node, struct node *parent, void *arg,
+			  int (*func)(const void *ctx, struct connection *conn,
+				      struct node *node, void *arg))
+{
+	int ret;
+
+	if (!func)
+		return WALK_TREE_OK;
+
+	ret = func(ctx, conn, node, arg);
+	if (ret == WALK_TREE_RM_CHILDENTRY && parent)
+		ret = rm_from_parent(conn, parent, node->name);
+
+	return ret;
+}
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg)
+{
+	int ret = 0;
+	void *tmpctx;
+	char *name;
+	struct node *node = NULL;
+	struct node *parent = NULL;
+
+	tmpctx = talloc_new(ctx);
+	if (!tmpctx) {
+		errno = ENOMEM;
+		return WALK_TREE_ERROR_STOP;
+	}
+	name = talloc_strdup(tmpctx, root);
+	if (!name) {
+		errno = ENOMEM;
+		talloc_free(tmpctx);
+		return WALK_TREE_ERROR_STOP;
+	}
+
+	/* Continue the walk until an error is returned. */
+	while (ret >= 0) {
+		/* node == NULL possible only for the initial loop iteration. */
+		if (node) {
+			/* Go one step up if ret or if last child finished. */
+			if (ret || node->childoff >= node->childlen) {
+				parent = node->parent;
+				/* Call function AFTER processing a node. */
+				ret = walk_call_func(ctx, conn, node, parent,
+						     arg, funcs->exit);
+				/* Last node, so exit loop. */
+				if (!parent)
+					break;
+				talloc_free(node);
+				/* Continue with parent. */
+				node = parent;
+				continue;
+			}
+			/* Get next child of current node. */
+			name = child_name(tmpctx, node->name,
+					  node->children + node->childoff);
+			if (!name) {
+				ret = WALK_TREE_ERROR_STOP;
+				break;
+			}
+			/* Point to next child. */
+			node->childoff += strlen(node->children +
+						 node->childoff) + 1;
+			/* Descent into children. */
+			parent = node;
+		}
+		/* Read next node (root node or next child). */
+		node = read_node(conn, tmpctx, name);
+		if (!node) {
+			/* Child not found - should not happen! */
+			/* ENOENT case can be handled by supplied function. */
+			if (errno == ENOENT && funcs->enoent)
+				ret = funcs->enoent(ctx, conn, parent, name,
+						    arg);
+			else
+				ret = WALK_TREE_ERROR_STOP;
+			if (!parent)
+				break;
+			if (ret == WALK_TREE_RM_CHILDENTRY)
+				ret = rm_from_parent(conn, parent, name);
+			if (ret < 0)
+				break;
+			talloc_free(name);
+			node = parent;
+			continue;
+		}
+		talloc_free(name);
+		node->parent = parent;
+		node->childoff = 0;
+		/* Call function BEFORE processing a node. */
+		ret = walk_call_func(ctx, conn, node, parent, arg,
+				     funcs->enter);
+	}
+
+	talloc_free(tmpctx);
+
+	return ret < 0 ? ret : WALK_TREE_OK;
+}
+
 static struct {
 	const char *str;
 	int (*func)(const void *ctx, struct connection *conn,
@@ -2284,18 +2413,6 @@ static int keys_equal_fn(void *key1, void *key2)
 	return 0 == strcmp((char *)key1, (char *)key2);
 }
 
-
-static char *child_name(const char *s1, const char *s2)
-{
-	if (strcmp(s1, "/")) {
-		return talloc_asprintf(NULL, "%s/%s", s1, s2);
-	}
-	else {
-		return talloc_asprintf(NULL, "/%s", s2);
-	}
-}
-
-
 int remember_string(struct hashtable *hash, const char *str)
 {
 	char *k = malloc(strlen(str) + 1);
@@ -2355,7 +2472,7 @@ static int check_store_(const char *name, struct hashtable *reachable)
 		while (i < node->childlen && !ret) {
 			struct node *childnode;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(node->name,
+			char * childname = child_name(NULL, node->name,
 						      node->children + i);
 
 			if (!childname) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index f7c37fe3b5..acb00ad969 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -202,6 +202,7 @@ struct node {
 
 	/* Children, each nul-terminated. */
 	unsigned int childlen;
+	unsigned int childoff;	/* Used by walk_node_tree() internally. */
 	char *children;
 
 	/* Allocation information for node currently in store. */
@@ -333,6 +334,45 @@ void read_state_buffered_data(const void *ctx, struct connection *conn,
 			      const struct xs_state_connection *sc);
 void read_state_node(const void *ctx, const void *state);
 
+/*
+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for
+ * each node. funcs->enter() is being called when entering a node, so before
+ * any of the children of the node is processed. funcs->exit() is being
+ * called when leaving the node, so after all children have been processed.
+ * funcs->enoent() is being called when a node isn't existing.
+ * funcs->*() return values:
+ *  < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value
+ *       in case WALK_TREE_ERROR_STOP is returned, errno should be set
+ *  WALK_TREE_OK: tree walk is continuing
+ *  WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but
+ *       walk continues
+ *  WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write
+ *       the modified parent node back to the data base, implies to not descend
+ *       below the current node, but to continue the walk
+ * funcs->*() is allowed to modify the node it is called for in the data base.
+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK
+ * in order to avoid descending into no longer existing children.
+ */
+/* Return values for funcs->*() and walk_node_tree(). */
+#define WALK_TREE_SUCCESS_STOP  -100    /* Stop walk early, no error. */
+#define WALK_TREE_ERROR_STOP    -1      /* Stop walk due to error. */
+#define WALK_TREE_OK            0       /* No error. */
+/* Return value for funcs->*() only. */
+#define WALK_TREE_SKIP_CHILDREN 1       /* Don't recurse below current node. */
+#define WALK_TREE_RM_CHILDENTRY 2       /* Remove child entry from parent. */
+
+struct walk_funcs {
+	int (*enter)(const void *ctx, struct connection *conn,
+		     struct node *node, void *arg);
+	int (*exit)(const void *ctx, struct connection *conn,
+		    struct node *node, void *arg);
+	int (*enoent)(const void *ctx, struct connection *conn,
+		      struct node *parent, char *name, void *arg);
+};
+
+int walk_node_tree(const void *ctx, struct connection *conn, const char *root,
+		   struct walk_funcs *funcs, void *arg);
+
 #endif /* _XENSTORED_CORE_H */
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:16:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:16:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435904.689809 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfI-0006X8-Ck; Wed, 02 Nov 2022 12:16:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435904.689809; Wed, 02 Nov 2022 12:16:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfI-0006Wz-9k; Wed, 02 Nov 2022 12:16:16 +0000
Received: by outflank-mailman (input) for mailman id 435904;
 Wed, 02 Nov 2022 12:16:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfH-0006Wg-25
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfH-0000yg-1Q
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfH-0001Yy-0j
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=CeMSyKYedJxvCtF5Hky7a5FUNuBo3PtmYA2QEjPsobk=; b=TbmkWLLZ9r1FYmiJ4IVaGqg+cc
	vwWaT79ZL417+tXKlBppdxT/37y1LQ6igusB+J8sQLs0CAdQrNwjvjiwUspM2RVdD5ETTxhSHds2Z
	Y1n2bAV67pxgX9Du8/Y6fEZe5ndlVz4UF5G1D9Hzk3i4tYrNA9YRkLF1oDI5DbgDPasE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: simplify check_store()
Message-Id: <E1oqCfH-0001Yy-0j@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:16:15 +0000

commit 70f719f52a220bc5bc987e4dd28e14a7039a176b
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: simplify check_store()
    
    check_store() is using a hash table for storing all node names it has
    found via walking the tree. Additionally it using another hash table
    for all children of a node to detect duplicate child names.
    
    Simplify that by dropping the second hash table as the first one is
    already holding all the needed information.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 47 +++++++++++++----------------------------
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index f78faf0c3e..b3596c7eeb 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2456,50 +2456,34 @@ static int check_store_(const char *name, struct hashtable *reachable)
 	if (node) {
 		size_t i = 0;
 
-		struct hashtable * children =
-			create_hashtable(16, hash_from_key_fn, keys_equal_fn);
-		if (!children) {
-			log("check_store create table: ENOMEM");
-			return ENOMEM;
-		}
-
 		if (!remember_string(reachable, name)) {
-			hashtable_destroy(children, 0);
 			log("check_store: ENOMEM");
 			return ENOMEM;
 		}
 
 		while (i < node->childlen && !ret) {
-			struct node *childnode;
+			struct node *childnode = NULL;
 			size_t childlen = strlen(node->children + i);
-			char * childname = child_name(NULL, node->name,
-						      node->children + i);
+			char *childname = child_name(NULL, node->name,
+						     node->children + i);
 
 			if (!childname) {
 				log("check_store: ENOMEM");
 				ret = ENOMEM;
 				break;
 			}
+
+			if (hashtable_search(reachable, childname)) {
+				log("check_store: '%s' is duplicated!",
+				    childname);
+				i = rm_child_entry(node, i, childlen);
+				goto next;
+			}
+
 			childnode = read_node(NULL, childname, childname);
-			
+
 			if (childnode) {
-				if (hashtable_search(children, childname)) {
-					log("check_store: '%s' is duplicated!",
-					    childname);
-					i = rm_child_entry(node, i, childlen);
-				}
-				else {
-					if (!remember_string(children,
-							     childname)) {
-						log("check_store: ENOMEM");
-						talloc_free(childnode);
-						talloc_free(childname);
-						ret = ENOMEM;
-						break;
-					}
-					ret = check_store_(childname,
-							   reachable);
-				}
+				ret = check_store_(childname, reachable);
 			} else if (errno != ENOMEM) {
 				log("check_store: No child '%s' found!\n",
 				    childname);
@@ -2509,19 +2493,18 @@ static int check_store_(const char *name, struct hashtable *reachable)
 				ret = ENOMEM;
 			}
 
+ next:
 			talloc_free(childnode);
 			talloc_free(childname);
 			i += childlen + 1;
 		}
 
-		hashtable_destroy(children, 0 /* Don't free values (they are
-						 all (void *)1) */);
 		talloc_free(node);
 	} else if (errno != ENOMEM) {
 		/* Impossible, because no database should ever be without the
 		   root, and otherwise, we've just checked in our caller
 		   (which made a recursive call to get here). */
-		   
+
 		log("check_store: No child '%s' found: impossible!", name);
 	} else {
 		log("check_store: ENOMEM");
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:16:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:16:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435905.689814 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfS-0006aO-GF; Wed, 02 Nov 2022 12:16:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435905.689814; Wed, 02 Nov 2022 12:16:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfS-0006aG-DC; Wed, 02 Nov 2022 12:16:26 +0000
Received: by outflank-mailman (input) for mailman id 435905;
 Wed, 02 Nov 2022 12:16:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfR-0006a3-4y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfR-0000yr-4L
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfR-0001ZT-3f
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=CuKJ4WD1UCL7td8hVQsCa6Bu5NFGtmjizWfjOv82Luc=; b=KJJTHybHAgcpNwJp1Uv8Tg1+yX
	QoKhBOkkP000KgOI/RrTxz3QRHtf8u0TDVh8mnrRa/uKcmcDCtfWd62M3qp3tyew8/UJHNfHYyJHt
	0tt3o+50xW8R48R0PEFBwtI2cn+3mg/QkQ4Gi0y1OOaZBOCXhmMA43ygqwq9Vlo8gueY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: use treewalk for check_store()
Message-Id: <E1oqCfR-0001ZT-3f@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:16:25 +0000

commit a07cc0ec60612f414bedf2bafb26ec38d2602e95
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: use treewalk for check_store()
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when checking the store for inconsistencies.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 106 ++++++++++------------------------------
 1 file changed, 26 insertions(+), 80 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b3596c7eeb..b0889186b6 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2423,18 +2423,6 @@ int remember_string(struct hashtable *hash, const char *str)
 	return hashtable_insert(hash, k, (void *)1);
 }
 
-static int rm_child_entry(struct node *node, size_t off, size_t len)
-{
-	if (!recovery)
-		return off;
-
-	if (remove_child_entry(NULL, node, off))
-		log("check_store: child entry could not be removed from '%s'",
-		    node->name);
-
-	return off - len - 1;
-}
-
 /**
  * A node has a children field that names the children of the node, separated
  * by NULs.  We check whether there are entries in there that are duplicated
@@ -2448,70 +2436,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len)
  * As we go, we record each node in the given reachable hashtable.  These
  * entries will be used later in clean_store.
  */
-static int check_store_(const char *name, struct hashtable *reachable)
+static int check_store_step(const void *ctx, struct connection *conn,
+			    struct node *node, void *arg)
 {
-	struct node *node = read_node(NULL, name, name);
-	int ret = 0;
-
-	if (node) {
-		size_t i = 0;
-
-		if (!remember_string(reachable, name)) {
-			log("check_store: ENOMEM");
-			return ENOMEM;
-		}
-
-		while (i < node->childlen && !ret) {
-			struct node *childnode = NULL;
-			size_t childlen = strlen(node->children + i);
-			char *childname = child_name(NULL, node->name,
-						     node->children + i);
-
-			if (!childname) {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-				break;
-			}
-
-			if (hashtable_search(reachable, childname)) {
-				log("check_store: '%s' is duplicated!",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-				goto next;
-			}
+	struct hashtable *reachable = arg;
 
-			childnode = read_node(NULL, childname, childname);
-
-			if (childnode) {
-				ret = check_store_(childname, reachable);
-			} else if (errno != ENOMEM) {
-				log("check_store: No child '%s' found!\n",
-				    childname);
-				i = rm_child_entry(node, i, childlen);
-			} else {
-				log("check_store: ENOMEM");
-				ret = ENOMEM;
-			}
+	if (hashtable_search(reachable, (void *)node->name)) {
+		log("check_store: '%s' is duplicated!", node->name);
+		return recovery ? WALK_TREE_RM_CHILDENTRY
+				: WALK_TREE_SKIP_CHILDREN;
+	}
 
- next:
-			talloc_free(childnode);
-			talloc_free(childname);
-			i += childlen + 1;
-		}
+	if (!remember_string(reachable, node->name))
+		return WALK_TREE_ERROR_STOP;
 
-		talloc_free(node);
-	} else if (errno != ENOMEM) {
-		/* Impossible, because no database should ever be without the
-		   root, and otherwise, we've just checked in our caller
-		   (which made a recursive call to get here). */
+	return WALK_TREE_OK;
+}
 
-		log("check_store: No child '%s' found: impossible!", name);
-	} else {
-		log("check_store: ENOMEM");
-		ret = ENOMEM;
-	}
+static int check_store_enoent(const void *ctx, struct connection *conn,
+			      struct node *parent, char *name, void *arg)
+{
+	log("check_store: node '%s' not found", name);
 
-	return ret;
+	return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK;
 }
 
 
@@ -2560,29 +2507,28 @@ static void clean_store(struct hashtable *reachable)
 
 void check_store(void)
 {
-	char *root = talloc_strdup(NULL, "/");
 	struct hashtable *reachable;
+	struct walk_funcs walkfuncs = {
+		.enter = check_store_step,
+		.enoent = check_store_enoent,
+	};
 
-	if (!root) {
-		log("check_store: ENOMEM");
-		return;
-	}
 	reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
 	if (!reachable) {
 		log("check_store: ENOMEM");
-		goto out_root;
+		return;
 	}
 
 	log("Checking store ...");
-	if (!check_store_(root, reachable) &&
-	    !check_transactions(reachable))
+	if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) {
+		if (errno == ENOMEM)
+			log("check_store: ENOMEM");
+	} else if (!check_transactions(reachable))
 		clean_store(reachable);
 	log("Checking store complete.");
 
 	hashtable_destroy(reachable, 0 /* Don't free values (they are all
 					  (void *)1) */);
- out_root:
-	talloc_free(root);
 }
 
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:16:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:16:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435906.689818 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfc-0006eo-Hs; Wed, 02 Nov 2022 12:16:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435906.689818; Wed, 02 Nov 2022 12:16:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfc-0006eg-Ew; Wed, 02 Nov 2022 12:16:36 +0000
Received: by outflank-mailman (input) for mailman id 435906;
 Wed, 02 Nov 2022 12:16:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfb-0006eT-86
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfb-0000z2-7V
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfb-0001Zw-6m
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=lYdEC0jh8ni1Covq48wyLjt6zyU9lAnor+DYUUnNK9k=; b=2ykLVhos6j4zcTMRxvah+xaNOG
	1nrcnt+AasQNvUqcDv0PWAHR6XPppxRwKOvIlWd/W3+ldnCqzwflQdtHj6859cqCkqbrbVyl/xEpa
	EgYM134gu7Q22PnE5+J/9U3ogEjw0aFKBUqkDH0UsT5ZAdoglDBHTCyHr952MuJ4gtjM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: use treewalk for deleting nodes
Message-Id: <E1oqCfb-0001Zw-6m@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:16:35 +0000

commit ea16962053a6849a6e7cada549ba7f8c586d85c6
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: use treewalk for deleting nodes
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when deleting a sub-tree of nodes.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 99 ++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b0889186b6..fa24bcfea4 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1330,21 +1330,6 @@ static int do_read(const void *ctx, struct connection *conn,
 	return 0;
 }
 
-static void delete_node_single(struct connection *conn, struct node *node)
-{
-	TDB_DATA key;
-
-	if (access_node(conn, node, NODE_ACCESS_DELETE, &key))
-		return;
-
-	if (do_tdb_delete(conn, &key, &node->acc) != 0) {
-		corrupt(conn, "Could not delete '%s'", node->name);
-		return;
-	}
-
-	domain_entry_dec(conn, node);
-}
-
 /* Must not be / */
 static char *basename(const char *name)
 {
@@ -1615,69 +1600,59 @@ static int remove_child_entry(struct connection *conn, struct node *node,
 	return write_node(conn, node, true);
 }
 
-static void delete_child(struct connection *conn,
-			 struct node *node, const char *childname)
+static int delete_child(struct connection *conn,
+			struct node *node, const char *childname)
 {
 	unsigned int i;
 
 	for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) {
 		if (streq(node->children+i, childname)) {
-			if (remove_child_entry(conn, node, i))
-				corrupt(conn, "Can't update parent node '%s'",
-					node->name);
-			return;
+			errno = remove_child_entry(conn, node, i) ? EIO : 0;
+			return errno;
 		}
 	}
 	corrupt(conn, "Can't find child '%s' in %s", childname, node->name);
+
+	errno = EIO;
+	return errno;
 }
 
-static int delete_node(struct connection *conn, const void *ctx,
-		       struct node *parent, struct node *node, bool watch_exact)
+static int delnode_sub(const void *ctx, struct connection *conn,
+		       struct node *node, void *arg)
 {
-	char *name;
+	const char *root = arg;
+	bool watch_exact;
+	int ret;
+	TDB_DATA key;
 
-	/* Delete children. */
-	while (node->childlen) {
-		struct node *child;
+	/* Any error here will probably be repeated for all following calls. */
+	ret = access_node(conn, node, NODE_ACCESS_DELETE, &key);
+	if (ret > 0)
+		return WALK_TREE_SUCCESS_STOP;
 
-		name = talloc_asprintf(node, "%s/%s", node->name,
-				       node->children);
-		child = name ? read_node(conn, node, name) : NULL;
-		if (child) {
-			if (delete_node(conn, ctx, node, child, true))
-				return errno;
-		} else {
-			trace("delete_node: Error deleting child '%s/%s'!\n",
-			      node->name, node->children);
-			/* Quit deleting. */
-			errno = ENOMEM;
-			return errno;
-		}
-		talloc_free(name);
-	}
+	/* In case of error stop the walk. */
+	if (!ret && do_tdb_delete(conn, &key, &node->acc))
+		return WALK_TREE_SUCCESS_STOP;
 
 	/*
 	 * Fire the watches now, when we can still see the node permissions.
 	 * This fine as we are single threaded and the next possible read will
 	 * be handled only after the node has been really removed.
-	 */
+	*/
+	watch_exact = strcmp(root, node->name);
 	fire_watches(conn, ctx, node->name, node, watch_exact, NULL);
-	delete_node_single(conn, node);
-	delete_child(conn, parent, basename(node->name));
-	talloc_free(node);
 
-	return 0;
+	domain_entry_dec(conn, node);
+
+	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, struct node *node,
-	       const char *name)
+static int _rm(struct connection *conn, const void *ctx, const char *name)
 {
-	/*
-	 * Deleting node by node, so the result is always consistent even in
-	 * case of a failure.
-	 */
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
+	struct walk_funcs walkfuncs = { .exit = delnode_sub };
+	int ret;
 
 	if (!parentname)
 		return errno;
@@ -1685,9 +1660,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node,
 	parent = read_node(conn, ctx, parentname);
 	if (!parent)
 		return read_node_can_propagate_errno() ? errno : EINVAL;
-	node->parent = parent;
 
-	return delete_node(conn, ctx, parent, node, false);
+	ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name);
+	if (ret < 0) {
+		if (ret == WALK_TREE_ERROR_STOP) {
+			corrupt(conn, "error when deleting sub-nodes of %s\n",
+				name);
+			errno = EIO;
+		}
+		return errno;
+	}
+
+	if (delete_child(conn, parent, basename(name)))
+		return errno;
+
+	return 0;
 }
 
 
@@ -1724,7 +1711,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, node, name);
+	ret = _rm(conn, ctx, name);
 	if (ret)
 		return ret;
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:16:47 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:16:47 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435907.689823 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfn-0006hj-JV; Wed, 02 Nov 2022 12:16:47 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435907.689823; Wed, 02 Nov 2022 12:16:47 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfn-0006hb-GR; Wed, 02 Nov 2022 12:16:47 +0000
Received: by outflank-mailman (input) for mailman id 435907;
 Wed, 02 Nov 2022 12:16:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfl-0006hM-BF
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfl-00010d-Ag
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfl-0001aN-9y
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=7S+pKJQEerE0/4cYVaydxug3JB4MIx+Tv9AHRjMDJEk=; b=6er6QJKxEXj3QAQVMd8ZMuiUkF
	Ctj/AK4AS8SGwFmRl92MMj5dOsO/GssdSBL5vAf8/R/nlZ9Kv46Kuxp+XJsVtUsj8Q/4voWyVmWXF
	pvghY/vfbG91TUfRVY7Fegz2i6YNOgV+qikKFgFF3SgKRkl7jIHEBWLOwwIQzjFJfeNU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: use treewalk for creating node records
Message-Id: <E1oqCfl-0001aN-9y@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:16:45 +0000

commit 297ac246a5d8ed656b349641288f3402dcc0251e
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: use treewalk for creating node records
    
    Instead of doing an open tree walk using call recursion, use
    walk_node_tree() when creating the node records during a live update.
    
    This will reduce code size and avoid many nesting levels of function
    calls which could potentially exhaust the stack.
    
    This is part of XSA-418 / CVE-2022-42321.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c | 105 +++++++++++++++-------------------------
 1 file changed, 40 insertions(+), 65 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index fa24bcfea4..bdc14679ad 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -3088,101 +3088,76 @@ const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms,
 	return NULL;
 }
 
-static const char *dump_state_node_tree(FILE *fp, char *path,
-					unsigned int path_max_len)
+struct dump_node_data {
+	FILE *fp;
+	const char *err;
+};
+
+static int dump_state_node_err(struct dump_node_data *data, const char *err)
 {
-	unsigned int pathlen, childlen, p = 0;
+	data->err = err;
+	return WALK_TREE_ERROR_STOP;
+}
+
+static int dump_state_node(const void *ctx, struct connection *conn,
+			   struct node *node, void *arg)
+{
+	struct dump_node_data *data = arg;
+	FILE *fp = data->fp;
+	unsigned int pathlen;
 	struct xs_state_record_header head;
 	struct xs_state_node sn;
-	TDB_DATA key, data;
-	const struct xs_tdb_record_hdr *hdr;
-	const char *child;
 	const char *ret;
 
-	pathlen = strlen(path) + 1;
-
-	set_tdb_key(path, &key);
-	data = tdb_fetch(tdb_ctx, key);
-	if (data.dptr == NULL)
-		return "Error reading node";
-
-	/* Clean up in case of failure. */
-	talloc_steal(path, data.dptr);
-
-	hdr = (void *)data.dptr;
+	pathlen = strlen(node->name) + 1;
 
 	head.type = XS_STATE_TYPE_NODE;
 	head.length = sizeof(sn);
 	sn.conn_id = 0;
 	sn.ta_id = 0;
 	sn.ta_access = 0;
-	sn.perm_n = hdr->num_perms;
+	sn.perm_n = node->perms.num;
 	sn.path_len = pathlen;
-	sn.data_len = hdr->datalen;
-	head.length += hdr->num_perms * sizeof(*sn.perms);
+	sn.data_len = node->datalen;
+	head.length += node->perms.num * sizeof(*sn.perms);
 	head.length += pathlen;
-	head.length += hdr->datalen;
+	head.length += node->datalen;
 	head.length = ROUNDUP(head.length, 3);
 
 	if (fwrite(&head, sizeof(head), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node head error");
 	if (fwrite(&sn, sizeof(sn), 1, fp) != 1)
-		return "Dump node state error";
+		return dump_state_node_err(data, "Dump node state error");
 
-	ret = dump_state_node_perms(fp, hdr->perms, hdr->num_perms);
+	ret = dump_state_node_perms(fp, node->perms.p, node->perms.num);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
+
+	if (fwrite(node->name, pathlen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node path error");
 
-	if (fwrite(path, pathlen, 1, fp) != 1)
-		return "Dump node path error";
-	if (hdr->datalen &&
-	    fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1)
-		return "Dump node data error";
+	if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1)
+		return dump_state_node_err(data, "Dump node data error");
 
 	ret = dump_state_align(fp);
 	if (ret)
-		return ret;
+		return dump_state_node_err(data, ret);
 
-	child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen;
-
-	/*
-	 * Use path for constructing children paths.
-	 * As we don't write out nodes without having written their parent
-	 * already we will never clobber a part of the path we'll need later.
-	 */
-	pathlen--;
-	if (path[pathlen - 1] != '/') {
-		path[pathlen] = '/';
-		pathlen++;
-	}
-	while (p < hdr->childlen) {
-		childlen = strlen(child) + 1;
-		if (pathlen + childlen > path_max_len)
-			return "Dump node path length error";
-		strcpy(path + pathlen, child);
-		ret = dump_state_node_tree(fp, path, path_max_len);
-		if (ret)
-			return ret;
-		p += childlen;
-		child += childlen;
-	}
-
-	talloc_free(data.dptr);
-
-	return NULL;
+	return WALK_TREE_OK;
 }
 
 const char *dump_state_nodes(FILE *fp, const void *ctx)
 {
-	char *path;
-
-	path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX + 1);
-	if (!path)
-		return "Path buffer allocation error";
+	struct dump_node_data data = {
+		.fp = fp,
+		.err = "Dump node walk error"
+	};
+	struct walk_funcs walkfuncs = { .enter = dump_state_node };
 
-	strcpy(path, "/");
+	if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data))
+		return data.err;
 
-	return dump_state_node_tree(fp, path, XENSTORE_ABS_PATH_MAX + 1);
+	return NULL;
 }
 
 void read_state_global(const void *ctx, const void *state)
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:16:56 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:16:56 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435908.689825 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfw-0006kX-Kq; Wed, 02 Nov 2022 12:16:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435908.689825; Wed, 02 Nov 2022 12:16:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCfw-0006kP-I1; Wed, 02 Nov 2022 12:16:56 +0000
Received: by outflank-mailman (input) for mailman id 435908;
 Wed, 02 Nov 2022 12:16:55 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfv-0006k7-EW
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:55 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfv-000117-Dp
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:55 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCfv-0001ao-D3
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:16:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=jnHCuwZK34/AjM38xRzh2WJGTy8y8JLtVPGEirhzjGQ=; b=NAtVR8fkmLKOHbyJyhl0Jjv4Dl
	0ROoEYIsKIvYIHS/zsD2+WBTf22XOS7Smb62RwFQvsQ/rkoOPKgLSjJyBWBKN/qC2XxRi4EbEO5hF
	JZIVB4+ZzLgYm2u/Om8KH8Q3mXibDXKtvjUfmvFiCdjay4Ed60n3oHolbF1+B4o5AtLY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: remove nodes owned by destroyed domain
Message-Id: <E1oqCfv-0001ao-D3@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:16:55 +0000

commit 755d3f9debf8879448211fffb018f556136f6a79
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:12 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: remove nodes owned by destroyed domain
    
    In case a domain is removed from Xenstore, remove all nodes owned by
    it per default.
    
    This tackles the problem that nodes might be created by a domain
    outside its home path in Xenstore, leading to Xenstore hogging more
    and more memory. Domain quota don't work in this case if the guest is
    rebooting in between.
    
    Since XSA-322 ownership of such stale nodes is transferred to dom0,
    which is helping against unintended access, but not against OOM of
    Xenstore.
    
    As a fallback for weird cases add a Xenstore start parameter for
    keeping today's way to handle stale nodes, adding the risk of Xenstore
    hitting an OOM situation.
    
    This is part of XSA-419 / CVE-2022-42322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c   | 17 +++++---
 tools/xenstore/xenstored_core.h   |  4 ++
 tools/xenstore/xenstored_domain.c | 84 +++++++++++++++++++++++++++++----------
 tools/xenstore/xenstored_domain.h |  2 +-
 4 files changed, 80 insertions(+), 27 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index bdc14679ad..13e48aaa73 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -80,6 +80,7 @@ static bool verbose = false;
 LIST_HEAD(connections);
 int tracefd = -1;
 static bool recovery = true;
+bool keep_orphans = false;
 static int reopen_log_pipe[2];
 static int reopen_log_pipe0_pollfd_idx = -1;
 char *tracefile = NULL;
@@ -753,7 +754,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 	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))
+	if (domain_adjust_node_perms(node))
 		goto error;
 
 	/* If owner is gone reset currently accounted memory size. */
@@ -796,7 +797,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 	void *p;
 	struct xs_tdb_record_hdr *hdr;
 
-	if (domain_adjust_node_perms(conn, node))
+	if (domain_adjust_node_perms(node))
 		return errno;
 
 	data.dsize = sizeof(*hdr)
@@ -1647,7 +1648,7 @@ static int delnode_sub(const void *ctx, struct connection *conn,
 	return WALK_TREE_RM_CHILDENTRY;
 }
 
-static int _rm(struct connection *conn, const void *ctx, const char *name)
+int rm_node(struct connection *conn, const void *ctx, const char *name)
 {
 	struct node *parent;
 	char *parentname = get_parent(ctx, name);
@@ -1711,7 +1712,7 @@ static int do_rm(const void *ctx, struct connection *conn,
 	if (streq(name, "/"))
 		return EINVAL;
 
-	ret = _rm(conn, ctx, name);
+	ret = rm_node(conn, ctx, name);
 	if (ret)
 		return ret;
 
@@ -2618,6 +2619,8 @@ static void usage(void)
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
 "  -I, --internal-db       store database in memory, not on disk\n"
+"  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
+"                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
 }
 
@@ -2642,6 +2645,7 @@ static struct option options[] = {
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
 	{ "internal-db", 0, NULL, 'I' },
+	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
 #ifndef NO_LIVE_UPDATE
@@ -2721,7 +2725,7 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2757,6 +2761,9 @@ int main(int argc, char *argv[])
 		case 'I':
 			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
 			break;
+		case 'K':
+			keep_orphans = true;
+			break;
 		case 'V':
 			verbose = true;
 			break;
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index acb00ad969..37006d508d 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -240,6 +240,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 struct node *read_node(struct connection *conn, const void *ctx,
 		       const char *name);
 
+/* Remove a node and its children. */
+int rm_node(struct connection *conn, const void *ctx, const char *name);
+
 void setup_structure(bool live_update);
 struct connection *new_connection(const struct interface_funcs *funcs);
 struct connection *get_connection_by_id(unsigned int conn_id);
@@ -284,6 +287,7 @@ extern int quota_req_outstanding;
 extern int quota_trans_nodes;
 extern int quota_memory_per_domain_soft;
 extern int quota_memory_per_domain_hard;
+extern bool keep_orphans;
 
 extern unsigned int timeout_watch_event_msec;
 
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 98b401fdec..84b7817cd5 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -227,10 +227,64 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
+				  struct node *node, void *arg)
+{
+	struct domain *domain = arg;
+	TDB_DATA key;
+	int ret = WALK_TREE_OK;
+
+	if (node->perms.p[0].id != domain->domid)
+		return WALK_TREE_OK;
+
+	if (keep_orphans) {
+		set_tdb_key(node->name, &key);
+		domain->nbentry--;
+		node->perms.p[0].id = priv_domid;
+		node->acc.memory = 0;
+		domain_entry_inc(NULL, node);
+		if (write_node_raw(NULL, &key, node, true)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when moving orphaned node %s to dom0\n",
+			       node->name);
+		} else
+			trace("orphaned node %s moved to dom0\n", node->name);
+	} else {
+		if (rm_node(NULL, ctx, node->name)) {
+			/* That's unfortunate. We only can try to continue. */
+			syslog(LOG_ERR,
+			       "error when deleting orphaned node %s\n",
+			       node->name);
+		} else
+			trace("orphaned node %s deleted\n", node->name);
+
+		/* Skip children in all cases in order to avoid more errors. */
+		ret = WALK_TREE_SKIP_CHILDREN;
+	}
+
+	return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP;
+}
+
+static void domain_tree_remove(struct domain *domain)
+{
+	int ret;
+	struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub };
+
+	if (domain->nbentry > 0) {
+		ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain);
+		if (ret == WALK_TREE_ERROR_STOP)
+			syslog(LOG_ERR,
+			       "error when looking for orphaned nodes\n");
+	}
+}
+
 static int destroy_domain(void *_domain)
 {
 	struct domain *domain = _domain;
 
+	domain_tree_remove(domain);
+
 	list_del(&domain->list);
 
 	if (!domain->introduced)
@@ -883,15 +937,15 @@ int domain_entry_inc(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return 0;
 
-	domid = node->perms.p ? node->perms.p[0].id : conn->id;
+	domid = node->perms.p[0].id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_inc(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_or_alloc_existing_domain(domid);
 		if (d)
 			d->nbentry++;
@@ -952,23 +1006,11 @@ int domain_alloc_permrefs(struct node_perms *perms)
  * Remove permissions for no longer existing domains in order to avoid a new
  * domain with the same domid inheriting the permissions.
  */
-int domain_adjust_node_perms(struct connection *conn, struct node *node)
+int domain_adjust_node_perms(struct node *node)
 {
 	unsigned int i;
 	int ret;
 
-	ret = chk_domain_generation(node->perms.p[0].id, node->generation);
-
-	/* If the owner doesn't exist any longer give it to priv domain. */
-	if (!ret) {
-		/*
-		 * In theory we'd need to update the number of dom0 nodes here,
-		 * but we could be called for a read of the node. So better
-		 * avoid the risk to overflow the node count of dom0.
-		 */
-		node->perms.p[0].id = priv_domid;
-	}
-
 	for (i = 1; i < node->perms.num; i++) {
 		if (node->perms.p[i].perms & XS_PERM_IGNORE)
 			continue;
@@ -986,15 +1028,15 @@ void domain_entry_dec(struct connection *conn, struct node *node)
 	struct domain *d;
 	unsigned int domid;
 
-	if (!conn)
+	if (!node->perms.p)
 		return;
 
 	domid = node->perms.p ? node->perms.p[0].id : conn->id;
 
-	if (conn->transaction) {
+	if (conn && conn->transaction) {
 		transaction_entry_dec(conn->transaction, domid);
 	} else {
-		d = (domid == conn->id && conn->domain) ? conn->domain
+		d = (conn && domid == conn->id && conn->domain) ? conn->domain
 		    : find_domain_struct(domid);
 		if (d) {
 			d->nbentry--;
@@ -1113,7 +1155,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check)
 		 * exist, as accounting is done either for a domain related to
 		 * the current connection, or for the domain owning a node
 		 * (which is always existing, as the owner of the node is
-		 * tested to exist and replaced by domid 0 if not).
+		 * tested to exist and deleted or replaced by domid 0 if not).
 		 * So not finding the related domain MUST be an error in the
 		 * data base.
 		 */
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 7fe0a21d9e..b38c82991d 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -62,7 +62,7 @@ const char *get_implicit_path(const struct connection *conn);
 bool domain_is_unprivileged(struct connection *conn);
 
 /* Remove node permissions for no longer existing domains. */
-int domain_adjust_node_perms(struct connection *conn, struct node *node);
+int domain_adjust_node_perms(struct node *node);
 int domain_alloc_permrefs(struct node_perms *perms);
 
 /* Quota manipulation */
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:17:06 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:17:06 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435909.689830 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCg6-0006oA-Nq; Wed, 02 Nov 2022 12:17:06 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435909.689830; Wed, 02 Nov 2022 12:17:06 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCg6-0006o2-L8; Wed, 02 Nov 2022 12:17:06 +0000
Received: by outflank-mailman (input) for mailman id 435909;
 Wed, 02 Nov 2022 12:17:05 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCg5-0006nu-Hk
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:05 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCg5-00011O-H2
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:05 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCg5-0001bM-G7
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:05 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=n8kDrv5NSGaqn55pw7gyAcRwn17dV/k9RQbftXLPYFw=; b=fQVIoIA0VPcuZo5yhl3jK3gqOz
	gA4EjvgkvRDGUCNy5MdE4PLAfVOtnNYm0MzUT6lsgAAEsRqLwgdCrGfOGda5IFoZ1Hiliel9YxQI5
	dj4rAiq3bzb+Uua6PyGgknJbT6aINu1q/D7mxRMJuYKRTiI1pGTe50N3cdlK8otSoma4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: make the internal memory data base the default
Message-Id: <E1oqCg5-0001bM-G7@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:17:05 +0000

commit d174fefa90487ddd25ebc618028f67b2e8a1f795
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: make the internal memory data base the default
    
    Having a file backed data base has the only advantage of being capable
    to dump the contents of it while Xenstore is running, and potentially
    using less swap space in case the data base can't be kept in memory.
    
    It has the major disadvantage of a huge performance overhead: switching
    to keep the data base in memory only speeds up live update of xenstored
    with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk
    of this configuration will be reduced from 7 seconds to 280 msecs
    (measured by "xenstore-control check").
    
    So make the internal memory data base the default and enhance the
    "--internal-db" command line parameter to take an optional parameter
    allowing to switch the internal data base back to the file based one.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/helpers/init-xenstore-domain.c |  4 ++--
 tools/xenstore/xenstored_core.c      | 13 ++++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 2d9ab6f1c5..04e351ca29 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -222,9 +222,9 @@ static int build(xc_interface *xch)
     }
 
     if ( param )
-        snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
+        snprintf(cmdline, 512, "--event %d %s", rv, param);
     else
-        snprintf(cmdline, 512, "--event %d --internal-db", rv);
+        snprintf(cmdline, 512, "--event %d", rv);
 
     dom->guest_domid = domid;
     dom->cmdline = xc_dom_strdup(dom, cmdline);
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 13e48aaa73..36fb4a8328 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -2308,7 +2308,7 @@ static void accept_connection(int sock)
 }
 #endif
 
-static int tdb_flags;
+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK;
 
 /* We create initial nodes manually. */
 static void manual_node(const char *name, const char *child)
@@ -2618,7 +2618,8 @@ static void usage(void)
 "                          watch-event: time a watch-event is kept pending\n"
 "  -R, --no-recovery       to request that no recovery should be attempted when\n"
 "                          the store is corrupted (debug only),\n"
-"  -I, --internal-db       store database in memory, not on disk\n"
+"  -I, --internal-db [on|off] store database in memory, not on disk, default is\n"
+"                          memory, with \"--internal-db off\" it is on disk\n"
 "  -K, --keep-orphans      don't delete nodes owned by a domain when the\n"
 "                          domain is deleted (this is a security risk!)\n"
 "  -V, --verbose           to request verbose execution.\n");
@@ -2644,7 +2645,7 @@ static struct option options[] = {
 	{ "quota-soft", 1, NULL, 'q' },
 	{ "timeout", 1, NULL, 'w' },
 	{ "no-recovery", 0, NULL, 'R' },
-	{ "internal-db", 0, NULL, 'I' },
+	{ "internal-db", 2, NULL, 'I' },
 	{ "keep-orphans", 0, NULL, 'K' },
 	{ "verbose", 0, NULL, 'V' },
 	{ "watch-nb", 1, NULL, 'W' },
@@ -2725,7 +2726,8 @@ int main(int argc, char *argv[])
 	orig_argc = argc;
 	orig_argv = argv;
 
-	while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U",
+	while ((opt = getopt_long(argc, argv,
+				  "DE:F:HI::KNPS:t:A:M:Q:q:T:RVW:w:U",
 				  options, NULL)) != -1) {
 		switch (opt) {
 		case 'D':
@@ -2759,7 +2761,8 @@ int main(int argc, char *argv[])
 			tracefile = optarg;
 			break;
 		case 'I':
-			tdb_flags = TDB_INTERNAL|TDB_NOLOCK;
+			if (optarg && !strcmp(optarg, "off"))
+				tdb_flags = 0;
 			break;
 		case 'K':
 			keep_orphans = true;
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:17:16 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:17:16 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435910.689835 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCgG-0006r2-PZ; Wed, 02 Nov 2022 12:17:16 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435910.689835; Wed, 02 Nov 2022 12:17:16 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCgG-0006qq-Md; Wed, 02 Nov 2022 12:17:16 +0000
Received: by outflank-mailman (input) for mailman id 435910;
 Wed, 02 Nov 2022 12:17:15 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgF-0006qc-Kf
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:15 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgF-00011S-Jy
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:15 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgF-0001dM-JG
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:15 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=66gtk2sQlfhaWdCTi3hGo4s0CbzdRVMZ3Ohxez0DoBg=; b=TG5p5McTPW1bbndUcE2QXmbNbv
	CUg6emJblm2TI1XA1nqZIccL8ETpcrDJu+eIDmEH8LFYISl3l9QVpW/2w4x5c3B7W9Ue+/QDkkRx4
	xdB8OaPZhL8nBAX+ZmXXwjIh04W7Eo0HVRTpT9hmUxyjCGibBylipXAYmkjCCk+/6+Wc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] docs: enhance xenstore.txt with permissions description
Message-Id: <E1oqCgF-0001dM-JG@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:17:15 +0000

commit d084d2c6dff7044956ebdf83a259ad6081a1d921
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    docs: enhance xenstore.txt with permissions description
    
    The permission scheme of Xenstore nodes is not really covered by
    docs/misc/xenstore.txt, other than referring to the Xen wiki.
    
    Add a paragraph explaining the permissions of nodes, and especially
    mentioning removal of nodes when a domain has been removed from
    Xenstore.
    
    This is part of XSA-419.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 docs/misc/xenstore.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt
index 988ef89cba..44428ae3a7 100644
--- a/docs/misc/xenstore.txt
+++ b/docs/misc/xenstore.txt
@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep
 them to within 2048 bytes.  (See XENSTORE_*_PATH_MAX in xs_wire.h.)
 
 
+Each node has one or multiple permission entries.  Permissions are
+granted by domain-id, the first permission entry of each node specifies
+the owner of the node.  Permissions of a node can be changed by the
+owner of the node, the owner can only be modified by the control
+domain (usually domain id 0).  The owner always has the right to read
+and write the node, while other permissions can be setup to allow
+read and/or write access.  When a domain is being removed from Xenstore
+nodes owned by that domain will be removed together with all of those
+nodes' children.
+
+
 Communication with xenstore is via either sockets, or event channel
 and shared memory, as specified in io/xs_wire.h: each message in
 either direction is a header formatted as a struct xsd_sockmsg
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:17:26 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:17:26 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435911.689838 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCgQ-0006tf-RB; Wed, 02 Nov 2022 12:17:26 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435911.689838; Wed, 02 Nov 2022 12:17:26 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCgQ-0006tV-OB; Wed, 02 Nov 2022 12:17:26 +0000
Received: by outflank-mailman (input) for mailman id 435911;
 Wed, 02 Nov 2022 12:17:25 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgP-0006tO-Nd
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:25 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgP-00011Z-N5
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:25 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgP-0001dn-MF
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:25 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=4IBlg5t3FZ+Z6qtSH6rQXhrx90si43Uq5NXs7j/FgAY=; b=MSh/8n0TLkYpXu8UfTmejMWWmu
	WthnoM5x3YHPtrPuc3sTy/2Cu2MyBg8Tz4Yr6B28WRktOHFbdLlywYrgZ+RjBeL5zF9PprRDnIGF1
	6/g/LNdwzcrIxClTS2mouZ9B9hJlb5J/rYFz6ZY7iv/JUkkbrtwP+EG3ulKrY1yP4gEw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml/xenstored: Fix quota bypass on domain shutdown
Message-Id: <E1oqCgP-0001dn-MF@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:17:25 +0000

commit db471408edd46af403b8bd44d180a928ad7fbb80
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:06 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml/xenstored: Fix quota bypass on domain shutdown
    
    XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of
    any nodes left after a domain is shutdown (e.g. outside its /local/domain/N
    tree).
    
    However Dom0 has no quota on purpose, so this opened up another potential
    attack vector. Avoid it by deleting these nodes instead of assigning them to
    Dom0.
    
    This is part of XSA-419 / CVE-2022-42323.
    
    Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains")
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/xenstored/perms.ml |  3 +--
 tools/ocaml/xenstored/store.ml | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
index e8a16221f8..84f2503e8e 100644
--- a/tools/ocaml/xenstored/perms.ml
+++ b/tools/ocaml/xenstored/perms.ml
@@ -64,8 +64,7 @@ let get_owner perm = perm.owner
 * *)
 let remove_domid ~domid perm =
 	let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in
-	let owner = if perm.owner = domid then 0 else perm.owner in
-	{ perm with acl; owner }
+	if perm.owner = domid then None else Some { perm with acl; owner = perm.owner }
 
 let default0 = create 0 NONE []
 
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 20e67b1427..70f0c83de4 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -87,10 +87,21 @@ let check_owner node connection =
 
 let rec recurse fct node = fct node; SymbolMap.iter (fun _ -> recurse fct) node.children
 
-(** [recurse_map f tree] applies [f] on each node in the tree recursively *)
-let recurse_map f =
+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively,
+    possibly removing some nodes.
+    Note that the nodes removed this way won't generate watch events.
+*)
+let recurse_filter_map f =
+	let invalid = -1 in
+	let is_valid _ node = node.perms.owner <> invalid in
 	let rec walk node =
-		f { node with children = SymbolMap.map walk node.children }
+		(* Map.filter_map is Ocaml 4.11+ only *)
+		let node =
+		{ node with children =
+			SymbolMap.map walk node.children |> SymbolMap.filter is_valid } in
+		match f node with
+		| Some keep -> keep
+		| None -> { node with perms = {node.perms with owner = invalid } }
 	in
 	walk
 
@@ -444,11 +455,13 @@ let setperms store perm path nperms =
 
 let reset_permissions store domid =
 	Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid;
-	store.root <- Node.recurse_map (fun node ->
-		let perms = Perms.Node.remove_domid ~domid node.perms in
-		if perms <> node.perms then
-			Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-		{ node with perms }
+	store.root <- Node.recurse_filter_map (fun node ->
+		match Perms.Node.remove_domid ~domid node.perms with
+		| None -> None
+		| Some perms ->
+			if perms <> node.perms then
+				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
+			Some { node with perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:17:36 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:17:36 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435912.689842 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCga-0006wG-So; Wed, 02 Nov 2022 12:17:36 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435912.689842; Wed, 02 Nov 2022 12:17:36 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCga-0006w8-Pk; Wed, 02 Nov 2022 12:17:36 +0000
Received: by outflank-mailman (input) for mailman id 435912;
 Wed, 02 Nov 2022 12:17:35 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgZ-0006vz-Qq
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:35 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgZ-00011d-QA
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:35 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgZ-0001eG-PJ
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:35 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=5sZ1507iXbJgRXT9bSY0plF2kgv49d5lny0l9el44eE=; b=2ivIO6J6MXvOYLJTFzhV1hN6Xx
	iWIZlVQCJJi+f7OmnscVhQsgXxiZNioewkIx4iK3aK6iH3hd/vZFLUaAKrRbfQ0eXahfu/fljIGCY
	OB7xVO6DUKBHNjJlJcEN8dYUqi2qMO89mndlu6xrSS+/t3IstXTd1Zn7HQ0RQ/xfjgS8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml: Ensure packet size is never negative
Message-Id: <E1oqCgZ-0001eG-PJ@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:17:35 +0000

commit ae34df4d82636f4c82700b447ea2c93b9f82b3f3
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Oct 12 19:13:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/ocaml: Ensure packet size is never negative
    
    Integers in Ocaml have 63 or 31 bits of signed precision.
    
    On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits
    within a 63-bit signed integer.
    
    In 32-bit builds of Ocaml, this goes wrong.  The C uint32_t is truncated
    first (loses the top bit), then has a unsigned/signed mismatch.
    
    A "negative" value (i.e. a packet on the ring of between 1G and 2G in size)
    will trigger an exception later in Bytes.make in xb.ml, and because the packet
    is not removed from the ring, the exception re-triggers on every subsequent
    query, creating a livelock.
    
    Fix both the source of the exception in Xb, and as defence in depth, mark the
    domain as bad for any Invalid_argument exceptions to avoid the risk of
    livelock.
    
    This is XSA-420 / CVE-2022-42324.
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 tools/ocaml/libs/xb/partial.ml   | 6 +++---
 tools/ocaml/xenstored/process.ml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
index b6e2a716e2..3aa8927eb7 100644
--- a/tools/ocaml/libs/xb/partial.ml
+++ b/tools/ocaml/libs/xb/partial.ml
@@ -36,7 +36,7 @@ let of_string s =
 	   This will leave the guest connection is a bad state and will
 	   be hard to recover from without restarting the connection
 	   (ie rebooting the guest) *)
-	let dlen = min xenstore_payload_max dlen in
+	let dlen = max 0 (min xenstore_payload_max dlen) in
 	{
 		tid = tid;
 		rid = rid;
@@ -46,8 +46,8 @@ let of_string s =
 	}
 
 let append pkt s sz =
-	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
-	Buffer.add_string pkt.buf (String.sub s 0 sz)
+	if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer";
+	Buffer.add_substring pkt.buf s 0 sz
 
 let to_complete pkt =
 	pkt.len - (Buffer.length pkt.buf)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
index 6781088387..72a79e9328 100644
--- a/tools/ocaml/xenstored/process.ml
+++ b/tools/ocaml/xenstored/process.ml
@@ -723,7 +723,7 @@ let do_input store cons doms con =
 			History.reconnect con;
 			info "%s reconnection complete" (Connection.get_domstr con);
 			None
-		| Failure exp ->
+		| Invalid_argument exp | Failure exp ->
 			error "caught exception %s" exp;
 			error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con));
 			Connection.mark_as_bad con;
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:17:46 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:17:46 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435913.689845 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCgk-0006zH-Tw; Wed, 02 Nov 2022 12:17:46 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435913.689845; Wed, 02 Nov 2022 12:17:46 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCgk-0006z9-RH; Wed, 02 Nov 2022 12:17:46 +0000
Received: by outflank-mailman (input) for mailman id 435913;
 Wed, 02 Nov 2022 12:17:45 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgj-0006z1-Tf
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:45 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgj-00011h-T4
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:45 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgj-0001eh-SP
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:45 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=luiA4u4jyC7oWSinQQ4bEiPMgJ6ouB6NFBFv0drtaJw=; b=U0n5i4BpkQXXNwhlXFlV/ZZ8/4
	de0rWuprjC1YbTVFI1qh6fhRVOqR3xgYEnd4l1gU+WFto+c5FEHNm7+50BQwhnpb+wkAiHn1PCqr5
	BaDnIlm1G1YhYj5P5G76LAUQBjIGnXXwtR3m693WdJx9I2W2HLfWeRYkDC4dQA9A2eo4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: fix deleting node in transaction
Message-Id: <E1oqCgj-0001eh-SP@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:17:45 +0000

commit 13ac37f1416cae88d97f7baf6cf2a827edb9a187
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:13 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: fix deleting node in transaction
    
    In case a node has been created in a transaction and it is later
    deleted in the same transaction, the transaction will be terminated
    with an error.
    
    As this error is encountered only when handling the deleted node at
    transaction finalization, the transaction will have been performed
    partially and without updating the accounting information. This will
    enable a malicious guest to create arbitrary number of nodes.
    
    This is part of XSA-421 / CVE-2022-42325.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_transaction.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 3e3eb47326..7ffe21bb52 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -418,7 +418,13 @@ static int finalize_transaction(struct connection *conn,
 						   true);
 				talloc_free(data.dptr);
 			} else {
-				ret = do_tdb_delete(conn, &key, NULL);
+				/*
+				 * A node having been created and later deleted
+				 * in this transaction will have no generation
+				 * information stored.
+				 */
+				ret = (i->generation == NO_GENERATION)
+				      ? 0 : do_tdb_delete(conn, &key, NULL);
 			}
 			if (ret)
 				goto err;
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 02 12:17:58 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 02 Nov 2022 12:17:58 +0000
Received: from list by lists.xenproject.org with outflank-mailman.435914.689850 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCgu-00071z-VU; Wed, 02 Nov 2022 12:17:56 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 435914.689850; Wed, 02 Nov 2022 12:17:56 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqCgu-00071r-Sj; Wed, 02 Nov 2022 12:17:56 +0000
Received: by outflank-mailman (input) for mailman id 435914;
 Wed, 02 Nov 2022 12:17:56 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgu-00071h-0i
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:56 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgu-00012B-06
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:56 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqCgt-0001f6-VV
 for xen-changelog@lists.xenproject.org; Wed, 02 Nov 2022 12:17:55 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=k0agSMyVAWZDYWleraQ0kULaisA22745wxDl/rxTh7U=; b=d5AGF1aEiu93yqFokpR+xwEvwl
	7rhGgyxVPWHtUjgyBIzaqfeaFTMVzWTUFuh4lBf5SlV3/ydXSZQZCjKDiqRaNJ65t4NbOIJoStIHD
	obVRiddd+NOqHiNe4G5o7zxoX3EXy4/dg9c4ybSrTTj3rW3V32ebdtKwRidOSOaAqImM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: harden transaction finalization against errors
Message-Id: <E1oqCgt-0001f6-VV@xenbits.xenproject.org>
Date: Wed, 02 Nov 2022 12:17:55 +0000

commit 2dd823ca7237e7fb90c890642d6a3b357a26fcff
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Tue Sep 13 07:35:14 2022 +0200
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 1 13:05:44 2022 +0000

    tools/xenstore: harden transaction finalization against errors
    
    When finalizing a transaction, any error occurring after checking for
    conflicts will result in the transaction being performed only
    partially today. Additionally accounting data will not be updated at
    the end of the transaction, which might result in further problems
    later.
    
    Avoid those problems by multiple modifications:
    
    - free any transaction specific nodes which don't need to be committed
      as they haven't been written during the transaction as soon as their
      generation count has been verified, this will reduce the risk of
      out-of-memory situations
    
    - store the transaction specific node name in struct accessed_node in
      order to avoid the need to allocate additional memory for it when
      finalizing the transaction
    
    - don't stop the transaction finalization when hitting an error
      condition, but try to continue to handle all modified nodes
    
    - in case of a detected error do the accounting update as needed and
      call the data base checking only after that
    
    - if writing a node in a transaction is failing (e.g. due to a failed
      quota check), fail the transaction, as prior changes to struct
      accessed_node can't easily be undone in that case
    
    This is part of XSA-421 / CVE-2022-42326.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Tested-by: Julien Grall <jgrall@amazon.com>
---
 tools/xenstore/xenstored_core.c        |  16 ++-
 tools/xenstore/xenstored_transaction.c | 171 +++++++++++++++------------------
 tools/xenstore/xenstored_transaction.h |   4 +-
 3 files changed, 92 insertions(+), 99 deletions(-)

diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 36fb4a8328..476d5c6d51 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -723,8 +723,7 @@ struct node *read_node(struct connection *conn, const void *ctx,
 		return NULL;
 	}
 
-	if (transaction_prepend(conn, name, &key))
-		return NULL;
+	transaction_prepend(conn, name, &key);
 
 	data = tdb_fetch(tdb_ctx, key);
 
@@ -842,10 +841,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node,
 static int write_node(struct connection *conn, struct node *node,
 		      bool no_quota_check)
 {
+	int ret;
+
 	if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key))
 		return errno;
 
-	return write_node_raw(conn, &node->key, node, no_quota_check);
+	ret = write_node_raw(conn, &node->key, node, no_quota_check);
+	if (ret && conn && conn->transaction) {
+		/*
+		 * Reverting access_node() is hard, so just fail the
+		 * transaction.
+		 */
+		fail_transaction(conn->transaction);
+	}
+
+	return ret;
 }
 
 unsigned int perm_for_conn(struct connection *conn,
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index 7ffe21bb52..ac854197ca 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -114,7 +114,8 @@ struct accessed_node
 	struct list_head list;
 
 	/* The name of the node. */
-	char *node;
+	char *trans_name;	/* Transaction specific name. */
+	char *node;		/* Main data base name. */
 
 	/* Generation count (or NO_GENERATION) for conflict checking. */
 	uint64_t generation;
@@ -199,25 +200,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans,
  * Prepend the transaction to name if node has been modified in the current
  * transaction.
  */
-int transaction_prepend(struct connection *conn, const char *name,
-			TDB_DATA *key)
+void transaction_prepend(struct connection *conn, const char *name,
+			 TDB_DATA *key)
 {
-	char *tdb_name;
+	struct accessed_node *i;
 
-	if (!conn || !conn->transaction ||
-	    !find_accessed_node(conn->transaction, name)) {
-		set_tdb_key(name, key);
-		return 0;
+	if (conn && conn->transaction) {
+		i = find_accessed_node(conn->transaction, name);
+		if (i) {
+			set_tdb_key(i->trans_name, key);
+			return;
+		}
 	}
 
-	tdb_name = transaction_get_node_name(conn->transaction,
-					     conn->transaction, name);
-	if (!tdb_name)
-		return errno;
-
-	set_tdb_key(tdb_name, key);
-
-	return 0;
+	set_tdb_key(name, key);
 }
 
 /*
@@ -240,7 +236,6 @@ int access_node(struct connection *conn, struct node *node,
 	struct accessed_node *i = NULL;
 	struct transaction *trans;
 	TDB_DATA local_key;
-	const char *trans_name = NULL;
 	int ret;
 	bool introduce = false;
 
@@ -259,10 +254,6 @@ int access_node(struct connection *conn, struct node *node,
 
 	trans = conn->transaction;
 
-	trans_name = transaction_get_node_name(node, trans, node->name);
-	if (!trans_name)
-		goto nomem;
-
 	i = find_accessed_node(trans, node->name);
 	if (!i) {
 		if (trans->nodes >= quota_trans_nodes &&
@@ -273,9 +264,10 @@ int access_node(struct connection *conn, struct node *node,
 		i = talloc_zero(trans, struct accessed_node);
 		if (!i)
 			goto nomem;
-		i->node = talloc_strdup(i, node->name);
-		if (!i->node)
+		i->trans_name = transaction_get_node_name(i, trans, node->name);
+		if (!i->trans_name)
 			goto nomem;
+		i->node = strchr(i->trans_name, '/') + 1;
 		if (node->generation != NO_GENERATION && node->perms.num) {
 			i->perms.p = talloc_array(i, struct xs_permissions,
 						  node->perms.num);
@@ -302,7 +294,7 @@ int access_node(struct connection *conn, struct node *node,
 			i->generation = node->generation;
 			i->check_gen = true;
 			if (node->generation != NO_GENERATION) {
-				set_tdb_key(trans_name, &local_key);
+				set_tdb_key(i->trans_name, &local_key);
 				ret = write_node_raw(conn, &local_key, node, true);
 				if (ret)
 					goto err;
@@ -321,7 +313,7 @@ int access_node(struct connection *conn, struct node *node,
 		return -1;
 
 	if (key) {
-		set_tdb_key(trans_name, key);
+		set_tdb_key(i->trans_name, key);
 		if (type == NODE_ACCESS_WRITE)
 			i->ta_node = true;
 		if (type == NODE_ACCESS_DELETE)
@@ -333,7 +325,6 @@ int access_node(struct connection *conn, struct node *node,
 nomem:
 	ret = ENOMEM;
 err:
-	talloc_free((void *)trans_name);
 	talloc_free(i);
 	trans->fail = true;
 	errno = ret;
@@ -371,100 +362,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact)
  * base.
  */
 static int finalize_transaction(struct connection *conn,
-				struct transaction *trans)
+				struct transaction *trans, bool *is_corrupt)
 {
-	struct accessed_node *i;
+	struct accessed_node *i, *n;
 	TDB_DATA key, ta_key, data;
 	struct xs_tdb_record_hdr *hdr;
 	uint64_t gen;
-	char *trans_name;
-	int ret;
 
-	list_for_each_entry(i, &trans->accessed, list) {
-		if (!i->check_gen)
-			continue;
+	list_for_each_entry_safe(i, n, &trans->accessed, list) {
+		if (i->check_gen) {
+			set_tdb_key(i->node, &key);
+			data = tdb_fetch(tdb_ctx, key);
+			hdr = (void *)data.dptr;
+			if (!data.dptr) {
+				if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
+					return EIO;
+				gen = NO_GENERATION;
+			} else
+				gen = hdr->generation;
+			talloc_free(data.dptr);
+			if (i->generation != gen)
+				return EAGAIN;
+		}
 
-		set_tdb_key(i->node, &key);
-		data = tdb_fetch(tdb_ctx, key);
-		hdr = (void *)data.dptr;
-		if (!data.dptr) {
-			if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST)
-				return EIO;
-			gen = NO_GENERATION;
-		} else
-			gen = hdr->generation;
-		talloc_free(data.dptr);
-		if (i->generation != gen)
-			return EAGAIN;
+		/* Entries for unmodified nodes can be removed early. */
+		if (!i->modified) {
+			if (i->ta_node) {
+				set_tdb_key(i->trans_name, &ta_key);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					return EIO;
+			}
+			list_del(&i->list);
+			talloc_free(i);
+		}
 	}
 
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
-		trans_name = transaction_get_node_name(i, trans, i->node);
-		if (!trans_name)
-			/* We are doomed: the transaction is only partial. */
-			goto err;
-
-		set_tdb_key(trans_name, &ta_key);
-
-		if (i->modified) {
-			set_tdb_key(i->node, &key);
-			if (i->ta_node) {
-				data = tdb_fetch(tdb_ctx, ta_key);
-				if (!data.dptr)
-					goto err;
+		set_tdb_key(i->node, &key);
+		if (i->ta_node) {
+			set_tdb_key(i->trans_name, &ta_key);
+			data = tdb_fetch(tdb_ctx, ta_key);
+			if (data.dptr) {
 				hdr = (void *)data.dptr;
 				hdr->generation = ++generation;
-				ret = do_tdb_write(conn, &key, &data, NULL,
-						   true);
+				*is_corrupt |= do_tdb_write(conn, &key, &data,
+							    NULL, true);
 				talloc_free(data.dptr);
+				if (do_tdb_delete(conn, &ta_key, NULL))
+					*is_corrupt = true;
 			} else {
-				/*
-				 * A node having been created and later deleted
-				 * in this transaction will have no generation
-				 * information stored.
-				 */
-				ret = (i->generation == NO_GENERATION)
-				      ? 0 : do_tdb_delete(conn, &key, NULL);
-			}
-			if (ret)
-				goto err;
-			if (i->fire_watch) {
-				fire_watches(conn, trans, i->node, NULL,
-					     i->watch_exact,
-					     i->perms.p ? &i->perms : NULL);
+				*is_corrupt = true;
 			}
+		} else {
+			/*
+			 * A node having been created and later deleted
+			 * in this transaction will have no generation
+			 * information stored.
+			 */
+			*is_corrupt |= (i->generation == NO_GENERATION)
+				       ? false
+				       : do_tdb_delete(conn, &key, NULL);
 		}
+		if (i->fire_watch)
+			fire_watches(conn, trans, i->node, NULL, i->watch_exact,
+				     i->perms.p ? &i->perms : NULL);
 
-		if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL))
-			goto err;
 		list_del(&i->list);
 		talloc_free(i);
 	}
 
 	return 0;
-
-err:
-	corrupt(conn, "Partial transaction");
-	return EIO;
 }
 
 static int destroy_transaction(void *_transaction)
 {
 	struct transaction *trans = _transaction;
 	struct accessed_node *i;
-	char *trans_name;
 	TDB_DATA key;
 
 	wrl_ntransactions--;
 	trace_destroy(trans, "transaction");
 	while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
 		if (i->ta_node) {
-			trans_name = transaction_get_node_name(i, trans,
-							       i->node);
-			if (trans_name) {
-				set_tdb_key(trans_name, &key);
-				do_tdb_delete(trans->conn, &key, NULL);
-			}
+			set_tdb_key(i->trans_name, &key);
+			do_tdb_delete(trans->conn, &key, NULL);
 		}
 		list_del(&i->list);
 		talloc_free(i);
@@ -556,6 +537,7 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 {
 	const char *arg = onearg(in);
 	struct transaction *trans;
+	bool is_corrupt = false;
 	int ret;
 
 	if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
@@ -579,13 +561,17 @@ int do_transaction_end(const void *ctx, struct connection *conn,
 		ret = transaction_fix_domains(trans, false);
 		if (ret)
 			return ret;
-		if (finalize_transaction(conn, trans))
-			return EAGAIN;
+		ret = finalize_transaction(conn, trans, &is_corrupt);
+		if (ret)
+			return ret;
 
 		wrl_apply_debit_trans_commit(conn);
 
 		/* fix domain entry for each changed domain */
 		transaction_fix_domains(trans, true);
+
+		if (is_corrupt)
+			corrupt(conn, "transaction inconsistency");
 	}
 	send_ack(conn, XS_TRANSACTION_END);
 
@@ -660,7 +646,7 @@ int check_transactions(struct hashtable *hash)
 	struct connection *conn;
 	struct transaction *trans;
 	struct accessed_node *i;
-	char *tname, *tnode;
+	char *tname;
 
 	list_for_each_entry(conn, &connections, list) {
 		list_for_each_entry(trans, &conn->transaction_list, list) {
@@ -672,11 +658,8 @@ int check_transactions(struct hashtable *hash)
 			list_for_each_entry(i, &trans->accessed, list) {
 				if (!i->ta_node)
 					continue;
-				tnode = transaction_get_node_name(tname, trans,
-								  i->node);
-				if (!tnode || !remember_string(hash, tnode))
+				if (!remember_string(hash, i->trans_name))
 					goto nomem;
-				talloc_free(tnode);
 			}
 
 			talloc_free(tname);
diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h
index 39d7f81c51..3417303f94 100644
--- a/tools/xenstore/xenstored_transaction.h
+++ b/tools/xenstore/xenstored_transaction.h
@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node,
 void queue_watches(struct connection *conn, const char *name, bool watch_exact);
 
 /* Prepend the transaction to name if appropriate. */
-int transaction_prepend(struct connection *conn, const char *name,
-                        TDB_DATA *key);
+void transaction_prepend(struct connection *conn, const char *name,
+                         TDB_DATA *key);
 
 /* Mark the transaction as failed. This will prevent it to be committed. */
 void fail_transaction(struct transaction *trans);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 03 01:55:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 03 Nov 2022 01:55:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.436086.690135 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqPRg-0002Qo-1k; Thu, 03 Nov 2022 01:55:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 436086.690135; Thu, 03 Nov 2022 01:55:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqPRf-0002Qf-Ul; Thu, 03 Nov 2022 01:55:03 +0000
Received: by outflank-mailman (input) for mailman id 436086;
 Thu, 03 Nov 2022 01:55:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqPRe-0002QZ-82
 for xen-changelog@lists.xenproject.org; Thu, 03 Nov 2022 01:55:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqPRd-0006Ax-Nd
 for xen-changelog@lists.xenproject.org; Thu, 03 Nov 2022 01:55:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqPRd-00071s-MR
 for xen-changelog@lists.xenproject.org; Thu, 03 Nov 2022 01:55:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Ftm2hFLhAp+OeeiStaeUu3HujWwo4Vou6O1SzKzmRew=; b=pXnwTSUZ5hJOSFUB2SvZf8AOja
	p6+KiE9ixHBIMzdI5AUz1A/R02Y6dgvLsC+cChJTBeNB01zJpco4r3wIcAA3B67bu9S/nERn8CO9I
	uA+wp7J6cAGXLs92uolb/OllZQKqHVlM10yGp/KmFgTRNbw2TztAJS1KuqseTPOMZ8dI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] x86/shadow: drop (replace) bogus assertions
Message-Id: <E1oqPRd-00071s-MR@xenbits.xenproject.org>
Date: Thu, 03 Nov 2022 01:55:01 +0000

commit 4d753ccf9ddf12332435f50d88e8cf0161e7a5b3
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Wed Nov 2 12:13:48 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:13:48 2022 +0100

    x86/shadow: drop (replace) bogus assertions
    
    The addition of a call to shadow_blow_tables() from shadow_teardown()
    has resulted in the "no vcpus" related assertion becoming triggerable:
    If domain_create() fails with at least one page successfully allocated
    in the course of shadow_enable(), or if domain_create() succeeds and
    the domain is then killed without ever invoking XEN_DOMCTL_max_vcpus.
    Note that in-tree tests (test-resource and test-tsx) do exactly the
    latter of these two.
    
    The assertion's comment was bogus anyway: Shadow mode has been getting
    enabled before allocation of vCPU-s for quite some time. Convert the
    assertion to a conditional: As long as there are no vCPU-s, there's
    nothing to blow away.
    
    Fixes: e7aa55c0aab3 ("x86/p2m: free the paging memory pool preemptively")
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    
    A similar assertion/comment pair exists in _shadow_prealloc(); the
    comment is similarly bogus, and the assertion could in principle trigger
    e.g. when shadow_alloc_p2m_page() is called early enough. Replace those
    at the same time by a similar early return, here indicating failure to
    the caller (which will generally lead to the domain being crashed in
    shadow_prealloc()).
    
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Roger Pau Monné <roger.pau@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    master commit: a92dc2bb30ba65ae25d2f417677eb7ef9a6a0fef
    master date: 2022-10-24 15:46:11 +0200
---
 xen/arch/x86/mm/shadow/common.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index e6af359579..cf1743488a 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -911,8 +911,9 @@ static bool __must_check _shadow_prealloc(struct domain *d, unsigned int pages)
         /* No reclaim when the domain is dying, teardown will take care of it. */
         return false;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to reclaim when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return false;
 
     /* Stage one: walk the list of pinned pages, unpinning them */
     perfc_incr(shadow_prealloc_1);
@@ -1000,8 +1001,9 @@ static void shadow_blow_tables(struct domain *d)
     mfn_t smfn;
     int i;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to do when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return;
 
     /* Pass one: unpin all pinned pages */
     foreach_pinned_shadow(d, sp, t)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Thu Nov 03 05:00:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 03 Nov 2022 05:00:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.436114.690183 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqSKi-0005YT-8a; Thu, 03 Nov 2022 05:00:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 436114.690183; Thu, 03 Nov 2022 05:00:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqSKi-0005Y4-5W; Thu, 03 Nov 2022 05:00:04 +0000
Received: by outflank-mailman (input) for mailman id 436114;
 Thu, 03 Nov 2022 05:00:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqSKf-0004oh-Tq
 for xen-changelog@lists.xenproject.org; Thu, 03 Nov 2022 05:00:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqSKf-00025x-Pe
 for xen-changelog@lists.xenproject.org; Thu, 03 Nov 2022 05:00:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqSKf-0007Bq-OY
 for xen-changelog@lists.xenproject.org; Thu, 03 Nov 2022 05:00:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=hZWg+Kl/vnUpmqZ6Zf98qlyWR3yrrYaRCW2D6lOCqWA=; b=Z8FtslAHD5QTJ4cCoHOTZpi0cx
	lVgG0U4L7DeHhg46Zywc0im7aOab5sWaQ7F5KDlng06xPPZUcufnXk61Nss6yKFHyDRnDabZliGCN
	npdS7Kplycyo0yB0n+7ZbE+TMtQp/afEYSSoen7CJxtXH6jaiCZuiRhdaVjpu3r0Duuc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] x86/shadow: drop (replace) bogus assertions
Message-Id: <E1oqSKf-0007Bq-OY@xenbits.xenproject.org>
Date: Thu, 03 Nov 2022 05:00:01 +0000

commit 6222bb8bd76a0f21048c852acd2542fa2494a907
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Wed Nov 2 12:12:30 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:12:30 2022 +0100

    x86/shadow: drop (replace) bogus assertions
    
    The addition of a call to shadow_blow_tables() from shadow_teardown()
    has resulted in the "no vcpus" related assertion becoming triggerable:
    If domain_create() fails with at least one page successfully allocated
    in the course of shadow_enable(), or if domain_create() succeeds and
    the domain is then killed without ever invoking XEN_DOMCTL_max_vcpus.
    Note that in-tree tests (test-resource and test-tsx) do exactly the
    latter of these two.
    
    The assertion's comment was bogus anyway: Shadow mode has been getting
    enabled before allocation of vCPU-s for quite some time. Convert the
    assertion to a conditional: As long as there are no vCPU-s, there's
    nothing to blow away.
    
    Fixes: e7aa55c0aab3 ("x86/p2m: free the paging memory pool preemptively")
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    
    A similar assertion/comment pair exists in _shadow_prealloc(); the
    comment is similarly bogus, and the assertion could in principle trigger
    e.g. when shadow_alloc_p2m_page() is called early enough. Replace those
    at the same time by a similar early return, here indicating failure to
    the caller (which will generally lead to the domain being crashed in
    shadow_prealloc()).
    
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Roger Pau Monné <roger.pau@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    master commit: a92dc2bb30ba65ae25d2f417677eb7ef9a6a0fef
    master date: 2022-10-24 15:46:11 +0200
---
 xen/arch/x86/mm/shadow/common.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index ba2ef80778..e803ac7866 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -942,8 +942,9 @@ static bool __must_check _shadow_prealloc(struct domain *d, unsigned int pages)
         /* No reclaim when the domain is dying, teardown will take care of it. */
         return false;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to reclaim when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return false;
 
     /* Stage one: walk the list of pinned pages, unpinning them */
     perfc_incr(shadow_prealloc_1);
@@ -1031,8 +1032,9 @@ static void shadow_blow_tables(struct domain *d)
     mfn_t smfn;
     int i;
 
-    /* Shouldn't have enabled shadows if we've no vcpus. */
-    ASSERT(d->vcpu && d->vcpu[0]);
+    /* Nothing to do when there are no vcpus yet. */
+    if ( !d->vcpu[0] )
+        return;
 
     /* Pass one: unpin all pinned pages */
     foreach_pinned_shadow(d, sp, t)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Fri Nov 04 04:44:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Fri, 04 Nov 2022 04:44:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.437268.691514 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqoYm-0005Dg-6h; Fri, 04 Nov 2022 04:44:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 437268.691514; Fri, 04 Nov 2022 04:44:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqoYm-0005DY-3p; Fri, 04 Nov 2022 04:44:04 +0000
Received: by outflank-mailman (input) for mailman id 437268;
 Fri, 04 Nov 2022 04:44:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoYk-0005DS-C2
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoYk-0005kJ-BB
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoYk-0002Jl-8h
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=QtoWBMOLnk5KdHmxb18xQjylp2JJAdMQL9H8vDj4+Us=; b=aC1ePxjpYP8vBpvPgFDUwf0eGx
	GEa8UYqSCnLKAv5NtMHuFfUGxWMN9Mq9NyVl9GB1Ob0O/i/SUM4rliozIwg2OzvsQrV9FZakhoR0V
	T+bcZ1AptGhM/W9TX6eg3iwOsrHvODYYmOLJb0dWjwIj10jRygZk9k416nSwM7sqjRDk=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] hvm/msr: load VIRT_SPEC_CTRL
Message-Id: <E1oqoYk-0002Jl-8h@xenbits.xenproject.org>
Date: Fri, 04 Nov 2022 04:44:02 +0000

commit 0d251a1dd15f9c406de2d7d7fe018c4e6e454215
Author:     Roger Pau Monné <roger.pau@citrix.com>
AuthorDate: Wed Nov 2 12:06:37 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:06:37 2022 +0100

    hvm/msr: load VIRT_SPEC_CTRL
    
    Add MSR_VIRT_SPEC_CTRL to the list of MSRs handled by
    hvm_load_cpu_msrs(), or else it would be lost.
    
    Fixes: 8ffd5496f4 ('amd/msr: implement VIRT_SPEC_CTRL for HVM guests on top of SPEC_CTRL')
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/arch/x86/hvm/hvm.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 44b432ec5a..15a9b34c59 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -1498,6 +1498,7 @@ static int cf_check hvm_load_cpu_msrs(struct domain *d, hvm_domain_context_t *h)
         case MSR_INTEL_MISC_FEATURES_ENABLES:
         case MSR_IA32_BNDCFGS:
         case MSR_IA32_XSS:
+        case MSR_VIRT_SPEC_CTRL:
         case MSR_AMD64_DR0_ADDRESS_MASK:
         case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
             rc = guest_wrmsr(v, ctxt->msr[i].index, ctxt->msr[i].val);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Fri Nov 04 04:44:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Fri, 04 Nov 2022 04:44:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.437269.691518 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqoYw-0005Fm-8F; Fri, 04 Nov 2022 04:44:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 437269.691518; Fri, 04 Nov 2022 04:44:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqoYw-0005Fe-5J; Fri, 04 Nov 2022 04:44:14 +0000
Received: by outflank-mailman (input) for mailman id 437269;
 Fri, 04 Nov 2022 04:44:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoYu-0005FT-G1
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoYu-0005kN-FG
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoYu-0002KC-EJ
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ZbcX/CB/Jnq4h5IXXJVZvFeRdV/Np0iqtw4o/Zk9Sf4=; b=L+f+HIdYXtUiUUG2RA852psvD6
	GdN91FO+rZ20XEFY06nTxSTSMtjdQpnypRxLNM5As0vUgLqr6BVgcZpD6LFtipDpXWE0ae5jahBDp
	BfTF7stmLpEYdLLVtIX4Z8FxHery/DcQmBJOIiVBEBcZIqx+fUOuIOWti03d6U9Bz/Fs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: remove XEN_LIB_STORED and XENSTORED_ROOTDIR
Message-Id: <E1oqoYu-0002KC-EJ@xenbits.xenproject.org>
Date: Fri, 04 Nov 2022 04:44:12 +0000

commit 1283af6465cd14934e89a088f8abef577d013761
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 2 12:07:57 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:07:57 2022 +0100

    tools/xenstore: remove XEN_LIB_STORED and XENSTORED_ROOTDIR
    
    XEN_LIB_STORED is serving no real purpose, as it is a mount point for
    a tmpfs, so it can be replaced easily by XEN_RUN_STORED.
    
    XENSTORED_ROOTDIR is basically unused already, there is just a single
    reference in xs_daemon_rootdir() with a fallback to XEN_LIB_STORED,
    and a .gdbinit file setting it.
    
    Remove the .gdbinit file, as it is not known having been used since
    ages, and make xs_daemon_rootdir() an alias of xs_daemon_rundir().
    
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 config/Paths.mk.in                                     |  1 -
 configure                                              |  4 ----
 docs/configure                                         |  4 ----
 m4/paths.m4                                            |  3 ---
 tools/configure                                        |  7 +------
 tools/configure.ac                                     |  1 -
 tools/hotplug/FreeBSD/rc.d/xencommons.in               |  6 ------
 tools/hotplug/Linux/systemd/Makefile                   |  1 -
 tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in | 12 ------------
 tools/libs/store/Makefile                              |  1 -
 tools/xenstore/.gdbinit                                |  4 ----
 tools/xenstore/Makefile                                |  4 ----
 tools/xenstore/Makefile.common                         |  1 -
 tools/xenstore/xs_lib.c                                | 11 +++++------
 14 files changed, 6 insertions(+), 54 deletions(-)

diff --git a/config/Paths.mk.in b/config/Paths.mk.in
index 416fc7aab9..44bab1d748 100644
--- a/config/Paths.mk.in
+++ b/config/Paths.mk.in
@@ -41,7 +41,6 @@ MAN8DIR                  := $(mandir)/man8
 XEN_RUN_DIR              := @XEN_RUN_DIR@
 XEN_LOG_DIR              := @XEN_LOG_DIR@
 XEN_LIB_DIR              := @XEN_LIB_DIR@
-XEN_LIB_STORED           := @XEN_LIB_STORED@
 XEN_RUN_STORED           := @XEN_RUN_STORED@
 
 CONFIG_DIR               := @CONFIG_DIR@
diff --git a/configure b/configure
index bb7f27ddad..b51174f2ef 100755
--- a/configure
+++ b/configure
@@ -603,7 +603,6 @@ INITD_DIR
 SHAREDIR
 XEN_LIB_DIR
 XEN_RUN_STORED
-XEN_LIB_STORED
 XEN_LOG_DIR
 XEN_RUN_DIR
 XENFIRMWAREDIR
@@ -2081,9 +2080,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-XEN_LIB_STORED=$localstatedir/lib/xenstored
-
-
 XEN_RUN_STORED=$rundir_path/xenstored
 
 
diff --git a/docs/configure b/docs/configure
index d4fced9858..f008ca0565 100755
--- a/docs/configure
+++ b/docs/configure
@@ -601,7 +601,6 @@ INITD_DIR
 SHAREDIR
 XEN_LIB_DIR
 XEN_RUN_STORED
-XEN_LIB_STORED
 XEN_LOG_DIR
 XEN_RUN_DIR
 XENFIRMWAREDIR
@@ -1984,9 +1983,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-XEN_LIB_STORED=$localstatedir/lib/xenstored
-
-
 XEN_RUN_STORED=$rundir_path/xenstored
 
 
diff --git a/m4/paths.m4 b/m4/paths.m4
index 826faada45..e4104bcce0 100644
--- a/m4/paths.m4
+++ b/m4/paths.m4
@@ -136,9 +136,6 @@ XEN_LOG_DIR=$localstatedir/log/xen
 AC_SUBST(XEN_LOG_DIR)
 AC_DEFINE_UNQUOTED([XEN_LOG_DIR], ["$XEN_LOG_DIR"], [Xen's log dir])
 
-XEN_LIB_STORED=$localstatedir/lib/xenstored
-AC_SUBST(XEN_LIB_STORED)
-
 XEN_RUN_STORED=$rundir_path/xenstored
 AC_SUBST(XEN_RUN_STORED)
 
diff --git a/tools/configure b/tools/configure
index 6199823f5a..ffe3f48901 100755
--- a/tools/configure
+++ b/tools/configure
@@ -725,7 +725,6 @@ INITD_DIR
 SHAREDIR
 XEN_LIB_DIR
 XEN_RUN_STORED
-XEN_LIB_STORED
 XEN_LOG_DIR
 XEN_RUN_DIR
 XENFIRMWAREDIR
@@ -4065,9 +4064,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-XEN_LIB_STORED=$localstatedir/lib/xenstored
-
-
 XEN_RUN_STORED=$rundir_path/xenstored
 
 
@@ -10085,7 +10081,7 @@ fi
 
 if test "x$systemd" = "xy"; then :
 
-    ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/var-lib-xenstored.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service"
+    ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service"
 
 
 fi
@@ -10967,7 +10963,6 @@ do
     "ocaml/xenstored/oxenstored.conf") CONFIG_FILES="$CONFIG_FILES ocaml/xenstored/oxenstored.conf" ;;
     "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
     "hotplug/Linux/systemd/proc-xen.mount") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/proc-xen.mount" ;;
-    "hotplug/Linux/systemd/var-lib-xenstored.mount") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/var-lib-xenstored.mount" ;;
     "hotplug/Linux/systemd/xen-init-dom0.service") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/xen-init-dom0.service" ;;
     "hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service" ;;
     "hotplug/Linux/systemd/xen-watchdog.service") CONFIG_FILES="$CONFIG_FILES hotplug/Linux/systemd/xen-watchdog.service" ;;
diff --git a/tools/configure.ac b/tools/configure.ac
index 18e481d77e..3a2f6a2da9 100644
--- a/tools/configure.ac
+++ b/tools/configure.ac
@@ -482,7 +482,6 @@ AX_AVAILABLE_SYSTEMD()
 AS_IF([test "x$systemd" = "xy"], [
     AC_CONFIG_FILES([
     hotplug/Linux/systemd/proc-xen.mount
-    hotplug/Linux/systemd/var-lib-xenstored.mount
     hotplug/Linux/systemd/xen-init-dom0.service
     hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service
     hotplug/Linux/systemd/xen-watchdog.service
diff --git a/tools/hotplug/FreeBSD/rc.d/xencommons.in b/tools/hotplug/FreeBSD/rc.d/xencommons.in
index fddcce314c..7f7cda289f 100644
--- a/tools/hotplug/FreeBSD/rc.d/xencommons.in
+++ b/tools/hotplug/FreeBSD/rc.d/xencommons.in
@@ -14,7 +14,6 @@ export LD_LIBRARY_PATH
 
 name="xencommons"
 rcvar="xencommons_enable"
-start_precmd="xen_precmd"
 start_cmd="xen_startcmd"
 stop_cmd="xen_stop"
 status_cmd="xen_status"
@@ -30,11 +29,6 @@ XENSTORED_PIDFILE="@XEN_RUN_DIR@/xenstored.pid"
 load_rc_config $name
 : ${xencommons_enable:=no}
 
-xen_precmd()
-{
-	mkdir -p @XEN_LIB_STORED@ || exit 1
-}
-
 xen_startcmd()
 {
 	local time=0
diff --git a/tools/hotplug/Linux/systemd/Makefile b/tools/hotplug/Linux/systemd/Makefile
index 26df2a43b1..e29889156d 100644
--- a/tools/hotplug/Linux/systemd/Makefile
+++ b/tools/hotplug/Linux/systemd/Makefile
@@ -4,7 +4,6 @@ include $(XEN_ROOT)/tools/Rules.mk
 XEN_SYSTEMD_MODULES := xen.conf
 
 XEN_SYSTEMD_MOUNT := proc-xen.mount
-XEN_SYSTEMD_MOUNT += var-lib-xenstored.mount
 
 XEN_SYSTEMD_SERVICE := xenstored.service
 XEN_SYSTEMD_SERVICE += xenconsoled.service
diff --git a/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in b/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in
deleted file mode 100644
index 11a7d50edc..0000000000
--- a/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in
+++ /dev/null
@@ -1,12 +0,0 @@
-[Unit]
-Description=mount xenstore file system
-Requires=proc-xen.mount
-After=proc-xen.mount
-ConditionPathExists=/proc/xen/capabilities
-RefuseManualStop=true
-
-[Mount]
-What=xenstore
-Where=@XEN_LIB_STORED@
-Type=tmpfs
-Options=mode=755
diff --git a/tools/libs/store/Makefile b/tools/libs/store/Makefile
index 2334c953bb..3557a8c76d 100644
--- a/tools/libs/store/Makefile
+++ b/tools/libs/store/Makefile
@@ -18,7 +18,6 @@ include ../libs.mk
 # Include configure output (config.h)
 CFLAGS += -include $(XEN_ROOT)/tools/config.h
 CFLAGS += $(CFLAGS_libxentoolcore)
-CFLAGS += -DXEN_LIB_STORED="\"$(XEN_LIB_STORED)\""
 CFLAGS += -DXEN_RUN_STORED="\"$(XEN_RUN_STORED)\""
 
 vpath xs_lib.c $(XEN_ROOT)/tools/xenstore
diff --git a/tools/xenstore/.gdbinit b/tools/xenstore/.gdbinit
deleted file mode 100644
index 9a71b20ac4..0000000000
--- a/tools/xenstore/.gdbinit
+++ /dev/null
@@ -1,4 +0,0 @@
-set environment XENSTORED_RUNDIR=testsuite/tmp
-set environment XENSTORED_ROOTDIR=testsuite/tmp
-handle SIGUSR1 noprint nostop
-handle SIGPIPE noprint nostop
diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile
index 1b66190cc5..ce7a68178f 100644
--- a/tools/xenstore/Makefile
+++ b/tools/xenstore/Makefile
@@ -69,7 +69,6 @@ install: all
 	$(INSTALL_DIR) $(DESTDIR)$(bindir)
 ifeq ($(XENSTORE_XENSTORED),y)
 	$(INSTALL_DIR) $(DESTDIR)$(sbindir)
-	$(INSTALL_DIR) $(DESTDIR)$(XEN_LIB_STORED)
 	$(INSTALL_PROG) xenstored $(DESTDIR)$(sbindir)
 endif
 	$(INSTALL_PROG) xenstore-control $(DESTDIR)$(bindir)
@@ -85,9 +84,6 @@ uninstall:
 	rm -f $(DESTDIR)$(bindir)/xenstore-control
 ifeq ($(XENSTORE_XENSTORED),y)
 	rm -f $(DESTDIR)$(sbindir)/xenstored
-	if [ -d $(DESTDIR)$(XEN_LIB_STORED) ]; then \
-		rmdir --ignore-fail-on-non-empty $(DESTDIR)$(XEN_LIB_STORED); \
-	fi
 endif
 	if [ -d $(DESTDIR)$(includedir)/xenstore-compat ]; then \
 		rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/xenstore-compat; \
diff --git a/tools/xenstore/Makefile.common b/tools/xenstore/Makefile.common
index ddbac052ac..b18f95c103 100644
--- a/tools/xenstore/Makefile.common
+++ b/tools/xenstore/Makefile.common
@@ -16,7 +16,6 @@ CFLAGS += $(CFLAGS_libxenevtchn)
 CFLAGS += $(CFLAGS_libxenctrl)
 CFLAGS += $(CFLAGS_libxenguest)
 CFLAGS += $(CFLAGS_libxentoolcore)
-CFLAGS += -DXEN_LIB_STORED="\"$(XEN_LIB_STORED)\""
 CFLAGS += -DXEN_RUN_STORED="\"$(XEN_RUN_STORED)\""
 
 ifdef CONFIG_STUBDOM
diff --git a/tools/xenstore/xs_lib.c b/tools/xenstore/xs_lib.c
index 10fa4c3ad0..b9941c567c 100644
--- a/tools/xenstore/xs_lib.c
+++ b/tools/xenstore/xs_lib.c
@@ -26,18 +26,17 @@
 
 /* Common routines for the Xen store daemon and client library. */
 
-const char *xs_daemon_rootdir(void)
-{
-	char *s = getenv("XENSTORED_ROOTDIR");
-	return (s ? s : XEN_LIB_STORED);
-}
-
 const char *xs_daemon_rundir(void)
 {
 	char *s = getenv("XENSTORED_RUNDIR");
 	return (s ? s : XEN_RUN_STORED);
 }
 
+const char *xs_daemon_rootdir(void)
+{
+	return xs_daemon_rundir();
+}
+
 static const char *xs_daemon_path(void)
 {
 	static char buf[PATH_MAX];
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Fri Nov 04 04:44:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Fri, 04 Nov 2022 04:44:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.437270.691521 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqoZ5-0005Il-9Q; Fri, 04 Nov 2022 04:44:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 437270.691521; Fri, 04 Nov 2022 04:44:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqoZ5-0005Id-6m; Fri, 04 Nov 2022 04:44:23 +0000
Received: by outflank-mailman (input) for mailman id 437270;
 Fri, 04 Nov 2022 04:44:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoZ4-0005IR-Ir
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoZ4-0005mX-IB
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoZ4-0002Kh-HN
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Pswzksu2sf7ZZ6S/MpOhDwn1jcJxG3tL35doqnTsOjk=; b=mMDwh7sh6luTVOGKgNt6J7oa3l
	m4kge3l1kfRl2bOfohYtuOoqbH7KPeR5JEZ53559KilRV7/31xvOs6lVlzJoj2lCWpY2hWwz4d8cS
	rZ803BM8kArDwB7dXsNubicQBTE0sYi++U+pRpXdfXMDfaaCx4bFOsop+nHP05UML60w=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/xenstore: call remove_domid_from_perm() for special nodes
Message-Id: <E1oqoZ4-0002Kh-HN@xenbits.xenproject.org>
Date: Fri, 04 Nov 2022 04:44:22 +0000

commit 0751a75e3996cf6efd3925a90b4776660d8df2bc
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 2 12:08:22 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 2 12:08:22 2022 +0100

    tools/xenstore: call remove_domid_from_perm() for special nodes
    
    When destroying a domain, any stale permissions of the domain must be
    removed from the special nodes "@...", too. This was not done in the
    fix for XSA-322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/xenstore/xenstored_domain.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 84b7817cd5..aa86892fed 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -227,6 +227,27 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static void remove_domid_from_perm(struct node_perms *perms,
+				   struct domain *domain)
+{
+	unsigned int cur, new;
+
+	if (perms->p[0].id == domain->domid)
+		perms->p[0].id = priv_domid;
+
+	for (cur = new = 1; cur < perms->num; cur++) {
+		if (perms->p[cur].id == domain->domid)
+			continue;
+
+		if (new != cur)
+			perms->p[new] = perms->p[cur];
+
+		new++;
+	}
+
+	perms->num = new;
+}
+
 static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
 				  struct node *node, void *arg)
 {
@@ -277,6 +298,9 @@ static void domain_tree_remove(struct domain *domain)
 			syslog(LOG_ERR,
 			       "error when looking for orphaned nodes\n");
 	}
+
+	remove_domid_from_perm(&dom_release_perms, domain);
+	remove_domid_from_perm(&dom_introduce_perms, domain);
 }
 
 static int destroy_domain(void *_domain)
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Fri Nov 04 04:44:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Fri, 04 Nov 2022 04:44:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.437271.691525 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqoZF-0005Lm-BA; Fri, 04 Nov 2022 04:44:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 437271.691525; Fri, 04 Nov 2022 04:44:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oqoZF-0005Lf-8I; Fri, 04 Nov 2022 04:44:33 +0000
Received: by outflank-mailman (input) for mailman id 437271;
 Fri, 04 Nov 2022 04:44:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoZE-0005LY-M3
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoZE-0005mh-LL
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oqoZE-0002LA-KN
 for xen-changelog@lists.xenproject.org; Fri, 04 Nov 2022 04:44:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=GhdJIihRm+CeSzHBQC5aOrU2YO4Q2U7G50IS39GXUzc=; b=X4X+7UuT6Z8aMD9bNRmRXpOrCr
	bngVGlgzZjGrLgz/xmwNU5e5Hea0Pd8+VKfusAlnunUXVUadB3oUEao5wp6bo3CcNuKVU9pIPHjHL
	Ox4kFmegAD3W1ooxXhfSz3hlkLfMWON4uOJNFSXwiO1SOdMuHozNdB6rI9uMGwlGqu0I=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] IOMMU/VT-d: wire common device reserved memory API
Message-Id: <E1oqoZE-0002LA-KN@xenbits.xenproject.org>
Date: Fri, 04 Nov 2022 04:44:32 +0000

commit 2d9b3699136d20e354a94daefebbeefa9ceec7b6
Author:     Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
AuthorDate: Thu Nov 3 09:12:11 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Thu Nov 3 09:12:11 2022 +0100

    IOMMU/VT-d: wire common device reserved memory API
    
    Re-use rmrr= parameter handling code to handle common device reserved
    memory.
    
    Move MAX_USER_RMRR_PAGES limit enforcement to apply only to
    user-configured ranges, but not those from internal callers.
    
    Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
    Reviewed-by: Kevin Tian <kevin.tian@intel.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/drivers/passthrough/vtd/dmar.c | 196 +++++++++++++++++++++----------------
 1 file changed, 114 insertions(+), 82 deletions(-)

diff --git a/xen/drivers/passthrough/vtd/dmar.c b/xen/drivers/passthrough/vtd/dmar.c
index 367304c873..78c8bad151 100644
--- a/xen/drivers/passthrough/vtd/dmar.c
+++ b/xen/drivers/passthrough/vtd/dmar.c
@@ -861,113 +861,136 @@ static struct user_rmrr __initdata user_rmrrs[MAX_USER_RMRR];
 
 /* Macro for RMRR inclusive range formatting. */
 #define ERMRRU_FMT "[%lx-%lx]"
-#define ERMRRU_ARG(eru) eru.base_pfn, eru.end_pfn
+#define ERMRRU_ARG base_pfn, end_pfn
 
-static int __init add_user_rmrr(void)
+/* Returns 1 on success, 0 when ignoring and < 0 on error. */
+static int __init add_one_user_rmrr(unsigned long base_pfn,
+                                    unsigned long end_pfn,
+                                    unsigned int dev_count,
+                                    uint32_t *sbdf)
 {
     struct acpi_rmrr_unit *rmrr, *rmrru;
-    unsigned int idx, seg, i;
-    unsigned long base, end;
+    unsigned int idx, seg;
+    unsigned long base_iter;
     bool overlap;
 
-    for ( i = 0; i < nr_rmrr; i++ )
+    if ( iommu_verbose )
+        printk(XENLOG_DEBUG VTDPREFIX
+               "Adding RMRR for %d device ([0]: %#x) range "ERMRRU_FMT"\n",
+               dev_count, sbdf[0], ERMRRU_ARG);
+
+    if ( base_pfn > end_pfn )
     {
-        base = user_rmrrs[i].base_pfn;
-        end = user_rmrrs[i].end_pfn;
+        printk(XENLOG_ERR VTDPREFIX
+               "Invalid RMRR Range "ERMRRU_FMT"\n",
+               ERMRRU_ARG);
+        return 0;
+    }
 
-        if ( base > end )
+    overlap = false;
+    list_for_each_entry(rmrru, &acpi_rmrr_units, list)
+    {
+        if ( pfn_to_paddr(base_pfn) <= rmrru->end_address &&
+             rmrru->base_address <= pfn_to_paddr(end_pfn) )
         {
             printk(XENLOG_ERR VTDPREFIX
-                   "Invalid RMRR Range "ERMRRU_FMT"\n",
-                   ERMRRU_ARG(user_rmrrs[i]));
-            continue;
+                   "Overlapping RMRRs: "ERMRRU_FMT" and [%lx-%lx]\n",
+                   ERMRRU_ARG,
+                   paddr_to_pfn(rmrru->base_address),
+                   paddr_to_pfn(rmrru->end_address));
+            overlap = true;
+            break;
         }
+    }
+    /* Don't add overlapping RMRR. */
+    if ( overlap )
+        return 0;
 
-        if ( (end - base) >= MAX_USER_RMRR_PAGES )
+    base_iter = base_pfn;
+    do
+    {
+        if ( !mfn_valid(_mfn(base_iter)) )
         {
             printk(XENLOG_ERR VTDPREFIX
-                   "RMRR range "ERMRRU_FMT" exceeds "\
-                   __stringify(MAX_USER_RMRR_PAGES)" pages\n",
-                   ERMRRU_ARG(user_rmrrs[i]));
-            continue;
+                   "Invalid pfn in RMRR range "ERMRRU_FMT"\n",
+                   ERMRRU_ARG);
+            break;
         }
+    } while ( base_iter++ < end_pfn );
 
-        overlap = false;
-        list_for_each_entry(rmrru, &acpi_rmrr_units, list)
-        {
-            if ( pfn_to_paddr(base) <= rmrru->end_address &&
-                 rmrru->base_address <= pfn_to_paddr(end) )
-            {
-                printk(XENLOG_ERR VTDPREFIX
-                       "Overlapping RMRRs: "ERMRRU_FMT" and [%lx-%lx]\n",
-                       ERMRRU_ARG(user_rmrrs[i]),
-                       paddr_to_pfn(rmrru->base_address),
-                       paddr_to_pfn(rmrru->end_address));
-                overlap = true;
-                break;
-            }
-        }
-        /* Don't add overlapping RMRR. */
-        if ( overlap )
-            continue;
+    /* Invalid pfn in range as the loop ended before end_pfn was reached. */
+    if ( base_iter <= end_pfn )
+        return 0;
 
-        do
-        {
-            if ( !mfn_valid(_mfn(base)) )
-            {
-                printk(XENLOG_ERR VTDPREFIX
-                       "Invalid pfn in RMRR range "ERMRRU_FMT"\n",
-                       ERMRRU_ARG(user_rmrrs[i]));
-                break;
-            }
-        } while ( base++ < end );
+    rmrr = xzalloc(struct acpi_rmrr_unit);
+    if ( !rmrr )
+        return -ENOMEM;
 
-        /* Invalid pfn in range as the loop ended before end_pfn was reached. */
-        if ( base <= end )
-            continue;
+    rmrr->scope.devices = xmalloc_array(u16, dev_count);
+    if ( !rmrr->scope.devices )
+    {
+        xfree(rmrr);
+        return -ENOMEM;
+    }
 
-        rmrr = xzalloc(struct acpi_rmrr_unit);
-        if ( !rmrr )
-            return -ENOMEM;
+    seg = 0;
+    for ( idx = 0; idx < dev_count; idx++ )
+    {
+        rmrr->scope.devices[idx] = sbdf[idx];
+        seg |= PCI_SEG(sbdf[idx]);
+    }
+    if ( seg != PCI_SEG(sbdf[0]) )
+    {
+        printk(XENLOG_ERR VTDPREFIX
+               "Segments are not equal for RMRR range "ERMRRU_FMT"\n",
+               ERMRRU_ARG);
+        scope_devices_free(&rmrr->scope);
+        xfree(rmrr);
+        return 0;
+    }
 
-        rmrr->scope.devices = xmalloc_array(u16, user_rmrrs[i].dev_count);
-        if ( !rmrr->scope.devices )
-        {
-            xfree(rmrr);
-            return -ENOMEM;
-        }
+    rmrr->segment = seg;
+    rmrr->base_address = pfn_to_paddr(base_pfn);
+    /* Align the end_address to the end of the page */
+    rmrr->end_address = pfn_to_paddr(end_pfn) | ~PAGE_MASK;
+    rmrr->scope.devices_cnt = dev_count;
 
-        seg = 0;
-        for ( idx = 0; idx < user_rmrrs[i].dev_count; idx++ )
-        {
-            rmrr->scope.devices[idx] = user_rmrrs[i].sbdf[idx];
-            seg |= PCI_SEG(user_rmrrs[i].sbdf[idx]);
-        }
-        if ( seg != PCI_SEG(user_rmrrs[i].sbdf[0]) )
-        {
-            printk(XENLOG_ERR VTDPREFIX
-                   "Segments are not equal for RMRR range "ERMRRU_FMT"\n",
-                   ERMRRU_ARG(user_rmrrs[i]));
-            scope_devices_free(&rmrr->scope);
-            xfree(rmrr);
-            continue;
-        }
+    if ( register_one_rmrr(rmrr) )
+        printk(XENLOG_ERR VTDPREFIX
+               "Could not register RMMR range "ERMRRU_FMT"\n",
+               ERMRRU_ARG);
 
-        rmrr->segment = seg;
-        rmrr->base_address = pfn_to_paddr(user_rmrrs[i].base_pfn);
-        /* Align the end_address to the end of the page */
-        rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn) | ~PAGE_MASK;
-        rmrr->scope.devices_cnt = user_rmrrs[i].dev_count;
+    return 1;
+}
 
-        if ( register_one_rmrr(rmrr) )
-            printk(XENLOG_ERR VTDPREFIX
-                   "Could not register RMMR range "ERMRRU_FMT"\n",
-                   ERMRRU_ARG(user_rmrrs[i]));
-    }
+static int __init add_user_rmrr(void)
+{
+    unsigned int i;
+    int ret;
 
+    for ( i = 0; i < nr_rmrr; i++ )
+    {
+        ret = add_one_user_rmrr(user_rmrrs[i].base_pfn,
+                                user_rmrrs[i].end_pfn,
+                                user_rmrrs[i].dev_count,
+                                user_rmrrs[i].sbdf);
+        if ( ret < 0 )
+            return ret;
+    }
     return 0;
 }
 
+static int __init cf_check add_one_extra_rmrr(xen_pfn_t start, xen_ulong_t nr, u32 id, void *ctxt)
+{
+    u32 sbdf_array[] = { id };
+    return add_one_user_rmrr(start, start+nr, 1, sbdf_array);
+}
+
+static int __init add_extra_rmrr(void)
+{
+    return iommu_get_extra_reserved_device_memory(add_one_extra_rmrr, NULL);
+}
+
 #include <asm/tboot.h>
 /* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
 /* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
@@ -1010,7 +1033,7 @@ int __init acpi_dmar_init(void)
     {
         iommu_init_ops = &intel_iommu_init_ops;
 
-        return add_user_rmrr();
+        return add_user_rmrr() || add_extra_rmrr();
     }
 
     return ret;
@@ -1108,6 +1131,15 @@ static int __init cf_check parse_rmrr_param(const char *str)
         else
             end = start;
 
+        if ( (end - start) >= MAX_USER_RMRR_PAGES )
+        {
+            printk(XENLOG_ERR VTDPREFIX
+                    "RMRR range "ERMRRU_FMT" exceeds "\
+                    __stringify(MAX_USER_RMRR_PAGES)" pages\n",
+                    start, end);
+            return -E2BIG;
+        }
+
         user_rmrrs[nr_rmrr].base_pfn = start;
         user_rmrrs[nr_rmrr].end_pfn = end;
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Sat Nov 05 11:33:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Sat, 05 Nov 2022 11:33:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.438031.692424 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1orHQ6-0005Lg-Ii; Sat, 05 Nov 2022 11:33:02 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 438031.692424; Sat, 05 Nov 2022 11:33:02 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1orHQ6-0005LX-Fe; Sat, 05 Nov 2022 11:33:02 +0000
Received: by outflank-mailman (input) for mailman id 438031;
 Sat, 05 Nov 2022 11:33:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQ6-0005LR-0V
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQ5-00060y-Vv
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQ5-0003aQ-Up
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=DKhoEWSWU8O1JU8pK2HdU1PGxHTfVA65wl+DHUlRVCc=; b=byE5KeLMK9TH1kPVHVyycpfK8b
	H0l2qLeXYg7WBtW7AYmNrATiZyDiAzbFYOPBNMe3MV0v05bdibhzbM13ChOKAKY3z43CCXyrUkEy3
	JHm74H5acqOhrgyJnIY/bCRMEiJ7ahmu20EXmYaeuWKsJ9t32UZcOd50yijkxiujB3/o=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] drivers/char: suspend handling in XHCI console driver
Message-Id: <E1orHQ5-0003aQ-Up@xenbits.xenproject.org>
Date: Sat, 05 Nov 2022 11:33:01 +0000

commit 8e35b1a98d8d789aa428eae9ea8b64018af469c3
Author:     Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
AuthorDate: Fri Nov 4 08:53:20 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Fri Nov 4 08:53:20 2022 +0100

    drivers/char: suspend handling in XHCI console driver
    
    Similar to the EHCI driver - save/restore relevant BAR and command
    register, re-configure DbC on resume and stop/start timer.
    On resume trigger sending anything that was queued in the meantime.
    Save full BAR value, instead of just the address part, to ease restoring
    on resume.
    
    Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/drivers/char/xhci-dbc.c | 55 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c
index 43ed64a004..86f6df6bef 100644
--- a/xen/drivers/char/xhci-dbc.c
+++ b/xen/drivers/char/xhci-dbc.c
@@ -251,14 +251,17 @@ struct dbc {
     struct xhci_string_descriptor *dbc_str;
 
     pci_sbdf_t sbdf;
-    uint64_t xhc_mmio_phys;
+    uint64_t bar_val;
     uint64_t xhc_dbc_offset;
     void __iomem *xhc_mmio;
 
     bool enable; /* whether dbgp=xhci was set at all */
     bool open;
+    bool suspended;
     enum xhci_share share;
     unsigned int xhc_num; /* look for n-th xhc */
+    /* state saved across suspend */
+    uint16_t pci_cr;
 };
 
 static void *dbc_sys_map_xhc(uint64_t phys, size_t size)
@@ -358,8 +361,9 @@ static bool __init dbc_init_xhc(struct dbc *dbc)
 
     pci_conf_write16(dbc->sbdf, PCI_COMMAND, cmd);
 
-    dbc->xhc_mmio_phys = (bar0 & PCI_BASE_ADDRESS_MEM_MASK) | (bar1 << 32);
-    dbc->xhc_mmio = dbc_sys_map_xhc(dbc->xhc_mmio_phys, xhc_mmio_size);
+    dbc->bar_val = bar0 | (bar1 << 32);
+    dbc->xhc_mmio = dbc_sys_map_xhc(dbc->bar_val & PCI_BASE_ADDRESS_MEM_MASK,
+                                    xhc_mmio_size);
 
     if ( dbc->xhc_mmio == NULL )
         return false;
@@ -979,6 +983,9 @@ static bool dbc_ensure_running(struct dbc *dbc)
     uint32_t ctrl;
     uint16_t cmd;
 
+    if ( dbc->suspended )
+        return false;
+
     if ( dbc->share != XHCI_SHARE_NONE )
     {
         /*
@@ -1213,9 +1220,11 @@ static void __init cf_check dbc_uart_init_postirq(struct serial_port *port)
      * page, so keep it simple.
      */
     if ( rangeset_add_range(mmio_ro_ranges,
-                PFN_DOWN(uart->dbc.xhc_mmio_phys + uart->dbc.xhc_dbc_offset),
-                PFN_UP(uart->dbc.xhc_mmio_phys + uart->dbc.xhc_dbc_offset +
-                       sizeof(*uart->dbc.dbc_reg)) - 1) )
+                PFN_DOWN((uart->dbc.bar_val & PCI_BASE_ADDRESS_MEM_MASK) +
+                         uart->dbc.xhc_dbc_offset),
+                PFN_UP((uart->dbc.bar_val & PCI_BASE_ADDRESS_MEM_MASK) +
+                       uart->dbc.xhc_dbc_offset +
+                sizeof(*uart->dbc.dbc_reg)) - 1) )
         printk(XENLOG_INFO
                "Error while adding MMIO range of device to mmio_ro_ranges\n");
 #endif
@@ -1255,6 +1264,38 @@ static void cf_check dbc_uart_flush(struct serial_port *port)
         set_timer(&uart->timer, goal);
 }
 
+static void cf_check dbc_uart_suspend(struct serial_port *port)
+{
+    struct dbc_uart *uart = port->uart;
+    struct dbc *dbc = &uart->dbc;
+
+    dbc_pop_events(dbc);
+    stop_timer(&uart->timer);
+    dbc->pci_cr = pci_conf_read16(dbc->sbdf, PCI_COMMAND);
+    dbc->suspended = true;
+}
+
+static void cf_check dbc_uart_resume(struct serial_port *port)
+{
+    struct dbc_uart *uart = port->uart;
+    struct dbc *dbc = &uart->dbc;
+
+    pci_conf_write32(dbc->sbdf, PCI_BASE_ADDRESS_0, dbc->bar_val & 0xFFFFFFFF);
+    pci_conf_write32(dbc->sbdf, PCI_BASE_ADDRESS_1, dbc->bar_val >> 32);
+    pci_conf_write16(dbc->sbdf, PCI_COMMAND, dbc->pci_cr);
+
+    if ( !dbc_init_dbc(dbc) )
+    {
+        dbc_error("resume failed\n");
+        return;
+    }
+
+    dbc_enable_dbc(dbc);
+    dbc->suspended = false;
+    dbc_flush(dbc, &dbc->dbc_oring, &dbc->dbc_owork);
+    set_timer(&uart->timer, NOW() + MICROSECS(DBC_POLL_INTERVAL));
+}
+
 static struct uart_driver dbc_uart_driver = {
     .init_preirq = dbc_uart_init_preirq,
     .init_postirq = dbc_uart_init_postirq,
@@ -1262,6 +1303,8 @@ static struct uart_driver dbc_uart_driver = {
     .putc = dbc_uart_putc,
     .getc = dbc_uart_getc,
     .flush = dbc_uart_flush,
+    .suspend = dbc_uart_suspend,
+    .resume = dbc_uart_resume,
 };
 
 /* Those are accessed via DMA. */
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Sat Nov 05 11:33:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Sat, 05 Nov 2022 11:33:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.438032.692428 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1orHQH-0005P7-K5; Sat, 05 Nov 2022 11:33:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 438032.692428; Sat, 05 Nov 2022 11:33:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1orHQH-0005Oz-HN; Sat, 05 Nov 2022 11:33:13 +0000
Received: by outflank-mailman (input) for mailman id 438032;
 Sat, 05 Nov 2022 11:33:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQG-0005Oj-3K
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQG-000613-2b
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQG-0003aq-1l
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Hz6k3wml6cOd0zEFrNdr6YItQ+kMw5hprd3LCp8qUdc=; b=qeF9CbaKpT/nx5AnYMde42zpKe
	Yz6+ShJmTf7eXxxBzRf2zn2J+e25+8ZB9I8XL0tHa8Cp0R3zLFlFApUoT9XgrXy+tXEk2Nv0PdhFy
	hoz5CcAg3Frrvdo7nU70tjGacU5SAgwNYaqGsbFb44KGUNIkZ/ROWl3z630VKGW3f9tw=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen: fix generated code for calling hypercall handlers
Message-Id: <E1orHQG-0003aq-1l@xenbits.xenproject.org>
Date: Sat, 05 Nov 2022 11:33:12 +0000

commit 9f3e585ff5ecc606e386057f5cfa66b22fea2b93
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Fri Nov 4 08:54:57 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Fri Nov 4 08:54:57 2022 +0100

    xen: fix generated code for calling hypercall handlers
    
    The code generated for the call_handlers_*() macros needs to avoid
    undefined behavior when multiple handlers share the same priority.
    The issue is the hypercall number being unverified fed into the macros
    and then used to set a mask via "mask = 1ULL << <hypercall-number>".
    
    Avoid a shift amount of more than 63 by setting mask to zero in case
    the hypercall number is too large.
    
    Fixes: eca1f00d0227 ("xen: generate hypercall interface related code")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/scripts/gen_hypercall.awk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/scripts/gen_hypercall.awk b/xen/scripts/gen_hypercall.awk
index 34840c514f..9f7cfa298a 100644
--- a/xen/scripts/gen_hypercall.awk
+++ b/xen/scripts/gen_hypercall.awk
@@ -263,7 +263,7 @@ END {
         printf("#define call_handlers_%s(num, ret, a1, a2, a3, a4, a5) \\\n", ca);
         printf("({ \\\n");
         if (need_mask)
-            printf("    uint64_t mask = 1ULL << num; \\\n");
+            printf("    uint64_t mask = (num) > 63 ? 0 : 1ULL << (num); \\\n");
         printf("    ");
         for (pl = 1; pl <= n_prios[ca]; pl++) {
             if (prios[ca, p_list[pl]] > 1) {
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Sat Nov 05 11:33:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Sat, 05 Nov 2022 11:33:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.438034.692433 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1orHQR-0005SS-M9; Sat, 05 Nov 2022 11:33:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 438034.692433; Sat, 05 Nov 2022 11:33:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1orHQR-0005SK-Iz; Sat, 05 Nov 2022 11:33:23 +0000
Received: by outflank-mailman (input) for mailman id 438034;
 Sat, 05 Nov 2022 11:33:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQQ-0005S2-6k
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQQ-00061K-5x
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1orHQQ-0003bJ-55
 for xen-changelog@lists.xenproject.org; Sat, 05 Nov 2022 11:33:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=zgNFcU+vWKvEo1XU4NIF9Oo/uEHSVx0r12w+9HOEPYM=; b=wniT5X2IlL0QVV1WVfvwei2tg2
	SD8g+9my+q8KwXg0NYxC9zTqUgMKnA5uOa7n7frH7VNCoqu7aXETQjxE5UUOc5GtvH8pNzn795PZm
	CHHDg6E4bqn06RGPo38xAUKcVbmRRRs9a/lQBPaGmyLKVqaPfP+KuFHJuovmbNJHbx7w=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen/sched: migrate timers to correct cpus after suspend
Message-Id: <E1orHQQ-0003bJ-55@xenbits.xenproject.org>
Date: Sat, 05 Nov 2022 11:33:22 +0000

commit 37f82facd62f720fdcec104f72f86b8c6c214820
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Fri Nov 4 09:03:23 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Fri Nov 4 09:03:23 2022 +0100

    xen/sched: migrate timers to correct cpus after suspend
    
    Today all timers are migrated to cpu 0 when the system is being
    suspended. They are not migrated back after resuming the system again.
    
    This results (at least) to visible problems with the credit scheduler,
    as the timer isn't handled on the cpu it was expected to occur, which
    will result in an ASSERT() triggering. Other more subtle problems, like
    uninterrupted elongated time slices, are probable. The least effect
    will be worse performance on cpu 0 resulting from most scheduling
    related timer interrupts happening there after suspend/resume.
    
    Add migrating the scheduling related timers of a specific cpu from cpu
    0 back to its original cpu when that cpu has gone up when resuming the
    system.
    
    Fixes: 0763cd268789 ("xen/sched: don't disable scheduler on cpus during suspend")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
    Acked-by: Dario Faggioli <dfaggioli@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/common/sched/core.c    | 29 +++++++++++++++++++++++
 xen/common/sched/cpupool.c |  2 ++
 xen/common/sched/credit.c  | 13 +++++++++++
 xen/common/sched/private.h | 10 ++++++++
 xen/common/sched/rt.c      | 58 ++++++++++++++++++++++++++++++++--------------
 5 files changed, 94 insertions(+), 18 deletions(-)

diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index 23fa6845a8..43132ff6e0 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -1284,6 +1284,35 @@ static int cpu_disable_scheduler_check(unsigned int cpu)
     return 0;
 }
 
+/*
+ * Called after a cpu has come up again in a suspend/resume cycle.
+ * Migrate all timers for this cpu (they have been migrated to cpu 0 when the
+ * cpu was going down).
+ * Note that only timers related to a physical cpu are migrated, not the ones
+ * related to a vcpu or domain.
+ */
+void sched_migrate_timers(unsigned int cpu)
+{
+    struct sched_resource *sr;
+
+    rcu_read_lock(&sched_res_rculock);
+
+    sr = get_sched_res(cpu);
+
+    /*
+     * Note that on a system with parked cpus (e.g. smt=0 on Intel cpus) this
+     * will be called for the parked cpus, too, so the case for no scheduling
+     * resource being available must be considered.
+     */
+    if ( sr && sr->master_cpu == cpu )
+    {
+        migrate_timer(&sr->s_timer, cpu);
+        sched_move_timers(sr->scheduler, sr);
+    }
+
+    rcu_read_unlock(&sched_res_rculock);
+}
+
 /*
  * In general, this must be called with the scheduler lock held, because the
  * adjust_affinity hook may want to modify the vCPU state. However, when the
diff --git a/xen/common/sched/cpupool.c b/xen/common/sched/cpupool.c
index b2c6f520c3..bdf6030ab0 100644
--- a/xen/common/sched/cpupool.c
+++ b/xen/common/sched/cpupool.c
@@ -1035,6 +1035,8 @@ static int cf_check cpu_callback(
     case CPU_ONLINE:
         if ( system_state <= SYS_STATE_active )
             rc = cpupool_cpu_add(cpu);
+        else
+            sched_migrate_timers(cpu);
         break;
     case CPU_DOWN_PREPARE:
         /* Suspend/Resume don't change assignments of cpus to cpupools. */
diff --git a/xen/common/sched/credit.c b/xen/common/sched/credit.c
index 47945c2834..f2cd3d9da3 100644
--- a/xen/common/sched/credit.c
+++ b/xen/common/sched/credit.c
@@ -614,6 +614,18 @@ init_pdata(struct csched_private *prv, struct csched_pcpu *spc, int cpu)
     spc->nr_runnable = 0;
 }
 
+static void cf_check
+csched_move_timers(const struct scheduler *ops, struct sched_resource *sr)
+{
+    struct csched_private *prv = CSCHED_PRIV(ops);
+    struct csched_pcpu *spc = sr->sched_priv;
+
+    if ( sr->master_cpu == prv->master )
+        migrate_timer(&prv->master_ticker, prv->master);
+
+    migrate_timer(&spc->ticker, sr->master_cpu);
+}
+
 /* Change the scheduler of cpu to us (Credit). */
 static spinlock_t *cf_check
 csched_switch_sched(struct scheduler *new_ops, unsigned int cpu,
@@ -2264,6 +2276,7 @@ static const struct scheduler sched_credit_def = {
     .switch_sched   = csched_switch_sched,
     .alloc_domdata  = csched_alloc_domdata,
     .free_domdata   = csched_free_domdata,
+    .move_timers    = csched_move_timers,
 };
 
 REGISTER_SCHEDULER(sched_credit_def);
diff --git a/xen/common/sched/private.h b/xen/common/sched/private.h
index 0126a4bb9e..0527a8c70d 100644
--- a/xen/common/sched/private.h
+++ b/xen/common/sched/private.h
@@ -331,6 +331,8 @@ struct scheduler {
                                     struct xen_sysctl_scheduler_op *);
     void         (*dump_settings)  (const struct scheduler *);
     void         (*dump_cpu_state) (const struct scheduler *, int);
+    void         (*move_timers)    (const struct scheduler *,
+                                    struct sched_resource *);
 };
 
 static inline int sched_init(struct scheduler *s)
@@ -485,6 +487,13 @@ static inline int sched_adjust_cpupool(const struct scheduler *s,
     return s->adjust_global ? s->adjust_global(s, op) : 0;
 }
 
+static inline void sched_move_timers(const struct scheduler *s,
+                                     struct sched_resource *sr)
+{
+    if ( s->move_timers )
+        s->move_timers(s, sr);
+}
+
 static inline void sched_unit_pause_nosync(const struct sched_unit *unit)
 {
     struct vcpu *v;
@@ -622,6 +631,7 @@ struct cpu_rm_data *alloc_cpu_rm_data(unsigned int cpu, bool aff_alloc);
 void free_cpu_rm_data(struct cpu_rm_data *mem, unsigned int cpu);
 int schedule_cpu_rm(unsigned int cpu, struct cpu_rm_data *mem);
 int sched_move_domain(struct domain *d, struct cpupool *c);
+void sched_migrate_timers(unsigned int cpu);
 struct cpupool *cpupool_get_by_id(unsigned int poolid);
 void cpupool_put(struct cpupool *pool);
 int cpupool_add_domain(struct domain *d, unsigned int poolid);
diff --git a/xen/common/sched/rt.c b/xen/common/sched/rt.c
index 960a8033e2..05988cbd3d 100644
--- a/xen/common/sched/rt.c
+++ b/xen/common/sched/rt.c
@@ -750,6 +750,27 @@ rt_switch_sched(struct scheduler *new_ops, unsigned int cpu,
     return &prv->lock;
 }
 
+static void move_repl_timer(struct rt_private *prv, unsigned int old_cpu)
+{
+    cpumask_t *online = get_sched_res(old_cpu)->cpupool->res_valid;
+    unsigned int new_cpu = cpumask_cycle(old_cpu, online);
+
+    /*
+     * Make sure the timer run on one of the cpus that are still available
+     * to this scheduler. If there aren't any left, it means it's the time
+     * to just kill it.
+     */
+    if ( new_cpu >= nr_cpu_ids )
+    {
+        kill_timer(&prv->repl_timer);
+        dprintk(XENLOG_DEBUG, "RTDS: timer killed on cpu %d\n", old_cpu);
+    }
+    else
+    {
+        migrate_timer(&prv->repl_timer, new_cpu);
+    }
+}
+
 static void cf_check
 rt_deinit_pdata(const struct scheduler *ops, void *pcpu, int cpu)
 {
@@ -759,25 +780,25 @@ rt_deinit_pdata(const struct scheduler *ops, void *pcpu, int cpu)
     spin_lock_irqsave(&prv->lock, flags);
 
     if ( prv->repl_timer.cpu == cpu )
-    {
-        cpumask_t *online = get_sched_res(cpu)->cpupool->res_valid;
-        unsigned int new_cpu = cpumask_cycle(cpu, online);
+        move_repl_timer(prv, cpu);
 
-        /*
-         * Make sure the timer run on one of the cpus that are still available
-         * to this scheduler. If there aren't any left, it means it's the time
-         * to just kill it.
-         */
-        if ( new_cpu >= nr_cpu_ids )
-        {
-            kill_timer(&prv->repl_timer);
-            dprintk(XENLOG_DEBUG, "RTDS: timer killed on cpu %d\n", cpu);
-        }
-        else
-        {
-            migrate_timer(&prv->repl_timer, new_cpu);
-        }
-    }
+    spin_unlock_irqrestore(&prv->lock, flags);
+}
+
+static void cf_check
+rt_move_timers(const struct scheduler *ops, struct sched_resource *sr)
+{
+    unsigned long flags;
+    struct rt_private *prv = rt_priv(ops);
+    unsigned int old_cpu;
+
+    spin_lock_irqsave(&prv->lock, flags);
+
+    old_cpu = prv->repl_timer.cpu;
+    if ( prv->repl_timer.status != TIMER_STATUS_invalid &&
+         prv->repl_timer.status != TIMER_STATUS_killed &&
+         !cpumask_test_cpu(old_cpu, sr->cpupool->res_valid) )
+        move_repl_timer(prv, old_cpu);
 
     spin_unlock_irqrestore(&prv->lock, flags);
 }
@@ -1556,6 +1577,7 @@ static const struct scheduler sched_rtds_def = {
     .sleep          = rt_unit_sleep,
     .wake           = rt_unit_wake,
     .context_saved  = rt_context_saved,
+    .move_timers    = rt_move_timers,
 };
 
 REGISTER_SCHEDULER(sched_rtds_def);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Tue Nov 08 09:22:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 08 Nov 2022 09:22:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.439798.693852 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osKnz-0003Fr-GC; Tue, 08 Nov 2022 09:22:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 439798.693852; Tue, 08 Nov 2022 09:22:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osKnz-0003Fk-DU; Tue, 08 Nov 2022 09:22:03 +0000
Received: by outflank-mailman (input) for mailman id 439798;
 Tue, 08 Nov 2022 09:22:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osKny-0003Fe-3T
 for xen-changelog@lists.xenproject.org; Tue, 08 Nov 2022 09:22:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osKny-0001EE-0v
 for xen-changelog@lists.xenproject.org; Tue, 08 Nov 2022 09:22:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osKnx-00052F-W4
 for xen-changelog@lists.xenproject.org; Tue, 08 Nov 2022 09:22:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=R/RSqHNwll7STu0wJhgLJqpIGSz/685+zM1A61lXhzQ=; b=DEsxwm8pH4ynW59NwrZdwoosZo
	s7VDOVerGzjlBxtx/UGCtEd1ux/G+60Nc92CboQYDRllgYp+zCx7uwc+VCBPbtQndvF60olOnWWaE
	S1MTvDk47cF+nchEw4+uLastqMpd6QnGTAyZugW6AQxMfLEJp+5FMrp4jD/wh2GbgGuc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen/arm: vGICv3: Emulate properly 32-bit access on GICR_PENDBASER
Message-Id: <E1osKnx-00052F-W4@xenbits.xenproject.org>
Date: Tue, 08 Nov 2022 09:22:01 +0000

commit a43e2b02df4156951fcba841ab3e15708c0701b0
Author:     Ayan Kumar Halder <ayankuma@amd.com>
AuthorDate: Thu Oct 27 19:55:55 2022 +0100
Commit:     Julien Grall <jgrall@amazon.com>
CommitDate: Mon Nov 7 18:56:57 2022 +0000

    xen/arm: vGICv3: Emulate properly 32-bit access on GICR_PENDBASER
    
    If a guest is running in 32 bit mode and it tries to access
    "GICR_PENDBASER + 4" mmio reg, it will be trapped to Xen. vreg_reg64_extract()
    will return the value stored "v->arch.vgic.rdist_pendbase + 4".
    This will be stored in a 64bit cpu register.
    So now we have the top 32 bits of GICR_PENDBASER (a 64 bit MMIO register) stored
    in the lower 32 bits of the 64bit cpu register.
    
    This 64bit cpu register is then modified bitwise with a mask (ie
    GICR_PENDBASER_PTZ, it clears the 62nd bit). But the PTZ (which is bit 30 in the
    64 bit cpu register) is not cleared as expected by the specification.
    
    The correct thing to do here is to store the value of
    "v->arch.vgic.rdist_pendbase" in a temporary 64 bit variable. This variable is
    then modified bitwise with GICR_PENDBASER_PTZ mask. It is then passed to
    vreg_reg64_extract() which will extract 32 bits from the given offset.
    
    Also, we have removed spin_lock_irqsave()/spin_unlock_irqrestore() to protect
    v->arch.vgic.rdist_pendbase in __vgic_v3_rdistr_rd_mmio_read(). The reason
    being v->arch.vgic.rdist_pendbase is now being read in an atomic manner.
    
    Similarly in __vgic_v3_rdistr_rd_mmio_write(), we have used read_atomic(),
    write_atomic() to read/write v->arch.vgic.rdist_pendbase.
    
    Fixes: fe7fa1332dabd9ce4 ("ARM: vGICv3: handle virtual LPI pending and property tables")
    Signed-off-by: Ayan Kumar Halder <ayankuma@amd.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
    Reviewed-by: Andre Przywara <andre.przywara@arm.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 xen/arch/arm/vgic-v3.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 7fb99a9ff2..c19691ece0 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -249,16 +249,15 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
 
     case VREG64(GICR_PENDBASER):
     {
-        unsigned long flags;
+        uint64_t val;
 
         if ( !v->domain->arch.vgic.has_its )
             goto read_as_zero_64;
         if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
 
-        spin_lock_irqsave(&v->arch.vgic.lock, flags);
-        *r = vreg_reg64_extract(v->arch.vgic.rdist_pendbase, info);
-        *r &= ~GICR_PENDBASER_PTZ;       /* WO, reads as 0 */
-        spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+        val = read_atomic(&v->arch.vgic.rdist_pendbase);
+        val &= ~GICR_PENDBASER_PTZ;      /* WO, reads as 0 */
+        *r = vreg_reg64_extract(val, info);
         return 1;
     }
 
@@ -577,10 +576,10 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
         /* Writing PENDBASER with LPIs enabled is UNPREDICTABLE. */
         if ( !(v->arch.vgic.flags & VGIC_V3_LPIS_ENABLED) )
         {
-            reg = v->arch.vgic.rdist_pendbase;
+            reg = read_atomic(&v->arch.vgic.rdist_pendbase);
             vreg_reg64_update(&reg, r, info);
             reg = sanitize_pendbaser(reg);
-            v->arch.vgic.rdist_pendbase = reg;
+            write_atomic(&v->arch.vgic.rdist_pendbase, reg);
         }
 
         spin_unlock_irqrestore(&v->arch.vgic.lock, false);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Tue Nov 08 09:22:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 08 Nov 2022 09:22:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.439799.693856 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osKo9-0003HZ-Hx; Tue, 08 Nov 2022 09:22:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 439799.693856; Tue, 08 Nov 2022 09:22:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osKo9-0003HR-F9; Tue, 08 Nov 2022 09:22:13 +0000
Received: by outflank-mailman (input) for mailman id 439799;
 Tue, 08 Nov 2022 09:22:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osKo8-0003HH-4z
 for xen-changelog@lists.xenproject.org; Tue, 08 Nov 2022 09:22:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osKo8-0001EI-4E
 for xen-changelog@lists.xenproject.org; Tue, 08 Nov 2022 09:22:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osKo8-00054D-3B
 for xen-changelog@lists.xenproject.org; Tue, 08 Nov 2022 09:22:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Sc1UY8yetZtfT6TtgrHwpuRJujHgv2nkXgmQscurYkQ=; b=wceZ2QPx2yru8NptfUYAfL3CUC
	DN5kRCRXnGE36+sCroFYBnXsPfNtEsQOps+AlYTtl1l1TaCWT3oEKrvaUhcj6Rw/9/Ct78GHJV4YK
	I6/urSNy6ISDIHzHpXFMq7caWCqVkmt5W958u4NyQolGScbNHL6qS5tOeBAmtm7QqdMs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen/arm: add iounmap after initrd has been loaded in domain_build
Message-Id: <E1osKo8-00054D-3B@xenbits.xenproject.org>
Date: Tue, 08 Nov 2022 09:22:12 +0000

commit e61a78981364925a43c9cc24dc77b62ff7b93c9f
Author:     Wei Chen <wei.chen@arm.com>
AuthorDate: Fri Nov 4 18:07:32 2022 +0800
Commit:     Julien Grall <jgrall@amazon.com>
CommitDate: Mon Nov 7 18:59:24 2022 +0000

    xen/arm: add iounmap after initrd has been loaded in domain_build
    
    domain_build use ioremap_wc to map a new non-cacheable virtual
    address for initrd. After Xen copy initrd from this address to
    guest, this new allocated virtual address has not been unmapped.
    
    So in this patch, we add an iounmap to the end of domain_build,
    after Xen loaded initrd to guest memory.
    
    Signed-off-by: Wei Chen <wei.chen@arm.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
---
 xen/arch/arm/domain_build.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 4fb5c20b13..bd30d3798c 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3418,6 +3418,8 @@ static void __init initrd_load(struct kernel_info *kinfo)
                                           initrd, len);
     if ( res != 0 )
         panic("Unable to copy the initrd in the hwdom memory\n");
+
+    iounmap(initrd);
 }
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 09 08:11:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 09 Nov 2022 08:11:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.440718.694848 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osgAp-0005pq-If; Wed, 09 Nov 2022 08:11:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 440718.694848; Wed, 09 Nov 2022 08:11:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osgAp-0005pi-Fh; Wed, 09 Nov 2022 08:11:03 +0000
Received: by outflank-mailman (input) for mailman id 440718;
 Wed, 09 Nov 2022 08:11:01 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osgAn-0005pc-Km
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 08:11:01 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osgAn-0007LV-Ju
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 08:11:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osgAn-0006sF-Ii
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 08:11:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=H/S067vRPbfldfDv+o9klV+awla155bbNW4ab4orU9M=; b=EHVfKRUBKp7SN4av2zEOcN/092
	VVpuT6HNKa8KcFV19HSUOHonTFvzxQu++kuk2bzGZiI8OF4Bjm9z4108OSv5omVVpbbTROxVqZyEI
	H2ut78hQKNejKWrRtGtOJbzHEkKMyP8OH1ZRfhm4x7qOeepWefjcQd2uUv0WIHi4HWpI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] x86/spec-ctrl: Enumeration for IBPB_RET
Message-Id: <E1osgAn-0006sF-Ii@xenbits.xenproject.org>
Date: Wed, 09 Nov 2022 08:11:01 +0000

commit c0de5d3b482d5ac84998ee44201796bc49be61ac
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Fri Nov 4 13:24:37 2022 +0000

    x86/spec-ctrl: Enumeration for IBPB_RET
    
    The IBPB_RET bit indicates that the CPU's implementation of MSR_PRED_CMD.IBPB
    does flush the RSB/RAS too.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 24496558e650535bdbd22cc04731e82276cd1b3f)
---
 tools/libxl/libxl_cpuid.c                   | 1 +
 tools/misc/xen-cpuid.c                      | 1 +
 xen/arch/x86/spec_ctrl.c                    | 5 +++--
 xen/include/public/arch-x86/cpufeatureset.h | 1 +
 4 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c
index 11b43807e9..694e554c96 100644
--- a/tools/libxl/libxl_cpuid.c
+++ b/tools/libxl/libxl_cpuid.c
@@ -275,6 +275,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
         {"ssb-no",       0x80000008, NA, CPUID_REG_EBX, 26,  1},
         {"psfd",         0x80000008, NA, CPUID_REG_EBX, 28,  1},
         {"btc-no",       0x80000008, NA, CPUID_REG_EBX, 29,  1},
+        {"ibpb-ret",     0x80000008, NA, CPUID_REG_EBX, 30,  1},
 
         {"nc",           0x80000008, NA, CPUID_REG_ECX,  0,  8},
         {"apicidsize",   0x80000008, NA, CPUID_REG_ECX, 12,  4},
diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c
index 52f5059d8f..d2add75f43 100644
--- a/tools/misc/xen-cpuid.c
+++ b/tools/misc/xen-cpuid.c
@@ -157,6 +157,7 @@ static const char *const str_e8b[32] =
     [24] = "amd-ssbd",         [25] = "virt-ssbd",
     [26] = "ssb-no",
     [28] = "psfd",             [29] = "btc-no",
+    [30] = "ibpb-ret",
 };
 
 static const char *const str_7d0[32] =
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index bfa5d27e00..23bc870d3c 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -418,7 +418,7 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
      * Hardware read-only information, stating immunity to certain issues, or
      * suggestions of which mitigation to use.
      */
-    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
            (caps & ARCH_CAPS_RDCL_NO)                        ? " RDCL_NO"        : "",
            (caps & ARCH_CAPS_IBRS_ALL)                       ? " IBRS_ALL"       : "",
            (caps & ARCH_CAPS_RSBA)                           ? " RSBA"           : "",
@@ -434,7 +434,8 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
            (e8b  & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS))   ? " STIBP_ALWAYS"   : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_FAST))      ? " IBRS_FAST"      : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_SAME_MODE)) ? " IBRS_SAME_MODE" : "",
-           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "");
+           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "",
+           (e8b  & cpufeat_mask(X86_FEATURE_IBPB_RET))       ? " IBPB_RET"       : "");
 
     /* Hardware features which need driving to mitigate issues. */
     printk("  Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s\n",
diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h
index 44b3ba331f..ddcfa5e807 100644
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -259,6 +259,7 @@ XEN_CPUFEATURE(VIRT_SSBD,     8*32+25) /*   MSR_VIRT_SPEC_CTRL.SSBD */
 XEN_CPUFEATURE(SSB_NO,        8*32+26) /*   Hardware not vulnerable to SSB */
 XEN_CPUFEATURE(PSFD,          8*32+28) /*   MSR_SPEC_CTRL.PSFD */
 XEN_CPUFEATURE(BTC_NO,        8*32+29) /*A  Hardware not vulnerable to Branch Type Confusion */
+XEN_CPUFEATURE(IBPB_RET,      8*32+30) /*A  IBPB clears RSB/RAS too. */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0.edx, word 9 */
 XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A  AVX512 Neural Network Instructions */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 09 08:11:12 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 09 Nov 2022 08:11:12 +0000
Received: from list by lists.xenproject.org with outflank-mailman.440719.694852 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osgAy-0005rs-KK; Wed, 09 Nov 2022 08:11:12 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 440719.694852; Wed, 09 Nov 2022 08:11:12 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osgAy-0005ri-HO; Wed, 09 Nov 2022 08:11:12 +0000
Received: by outflank-mailman (input) for mailman id 440719;
 Wed, 09 Nov 2022 08:11:11 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osgAx-0005ra-O2
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 08:11:11 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osgAx-0007Lc-NI
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 08:11:11 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osgAx-0006sj-ML
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 08:11:11 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=lIAgBJcgvhAQOjPr0IQZE8J2q4BtHR/Me4q0tjmHTUc=; b=Fi6FZi5yJ6RNhMVub8GNRyIH8m
	EB7jKYJkrWUTpVSSkYPKhICEQbYkYeZjJGJu3/U0abeHdZLqa3Nhm+Nkm8ZkRLwbugx8OiLwmv+cp
	bQzEZgc514AUdpZsASu7TuScAbwYt4nDoor+w3hBui/tEtTKMG/HwM4KvPAO9UJWKtZc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.13] x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
Message-Id: <E1osgAx-0006sj-ML@xenbits.xenproject.org>
Date: Wed, 09 Nov 2022 08:11:11 +0000

commit 1151d260d7a0186978b80b708fcb712eb1470f49
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Fri Nov 4 13:24:37 2022 +0000

    x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
    
    Introduce spec_ctrl_new_guest_context() to encapsulate all logic pertaining to
    using MSR_PRED_CMD for a new guest context, even if it only has one user
    presently.
    
    Introduce X86_BUG_IBPB_NO_RET, and use it extend spec_ctrl_new_guest_context()
    with a manual fixup for hardware which mis-implements IBPB.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 2b27967fb89d7904a1571a2fb963b1c9cac548db)
---
 xen/arch/x86/asm-macros.c         |  1 +
 xen/arch/x86/domain.c             |  2 +-
 xen/arch/x86/spec_ctrl.c          |  8 ++++++++
 xen/include/asm-x86/cpufeatures.h |  1 +
 xen/include/asm-x86/spec_ctrl.h   | 22 ++++++++++++++++++++++
 5 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/asm-macros.c b/xen/arch/x86/asm-macros.c
index b963d56a56..8c585697b9 100644
--- a/xen/arch/x86/asm-macros.c
+++ b/xen/arch/x86/asm-macros.c
@@ -1 +1,2 @@
 #include <asm/alternative-asm.h>
+#include <asm/spec_ctrl_asm.h>
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 6996c6b06a..c14cc724fa 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1814,7 +1814,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
              */
             if ( *last_id != next_id )
             {
-                wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+                spec_ctrl_new_guest_context();
                 *last_id = next_id;
             }
         }
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 23bc870d3c..0dbb7d5f87 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -773,6 +773,14 @@ static void __init ibpb_calculations(void)
         return;
     }
 
+    /*
+     * AMD/Hygon CPUs to date (June 2022) don't flush the the RAS.  Future
+     * CPUs are expected to enumerate IBPB_RET when this has been fixed.
+     * Until then, cover the difference with the software sequence.
+     */
+    if ( boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_IBPB_RET) )
+        setup_force_cpu_cap(X86_BUG_IBPB_NO_RET);
+
     /*
      * IBPB-on-entry mitigations for Branch Type Confusion.
      *
diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h
index c6136ca4a0..730eac4b2f 100644
--- a/xen/include/asm-x86/cpufeatures.h
+++ b/xen/include/asm-x86/cpufeatures.h
@@ -46,6 +46,7 @@ XEN_CPUFEATURE(IBPB_ENTRY_HVM,    X86_SYNTH(27)) /* MSR_PRED_CMD used by Xen for
 
 #define X86_BUG_FPU_PTRS          X86_BUG( 0) /* (F)X{SAVE,RSTOR} doesn't save/restore FOP/FIP/FDP. */
 #define X86_BUG_CLFLUSH_MFENCE    X86_BUG( 2) /* MFENCE needed to serialise CLFLUSH */
+#define X86_BUG_IBPB_NO_RET       X86_BUG( 3) /* IBPB doesn't flush the RSB/RAS */
 
 /* Total number of capability words, inc synth and bug words. */
 #define NCAPINTS (FSCAPINTS + X86_NR_SYNTH + X86_NR_BUG) /* N 32-bit words worth of info */
diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h
index 2f15ae9814..fcaef49629 100644
--- a/xen/include/asm-x86/spec_ctrl.h
+++ b/xen/include/asm-x86/spec_ctrl.h
@@ -65,6 +65,28 @@
 void init_speculation_mitigations(void);
 void spec_ctrl_init_domain(struct domain *d);
 
+/*
+ * Switch to a new guest prediction context.
+ *
+ * This flushes all indirect branch predictors (BTB, RSB/RAS), so guest code
+ * which has previously run on this CPU can't attack subsequent guest code.
+ *
+ * As this flushes the RSB/RAS, it destroys the predictions of the calling
+ * context.  For best performace, arrange for this to be used when we're going
+ * to jump out of the current context, e.g. with reset_stack_and_jump().
+ *
+ * For hardware which mis-implements IBPB, fix up by flushing the RSB/RAS
+ * manually.
+ */
+static always_inline void spec_ctrl_new_guest_context(void)
+{
+    wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+
+    /* (ab)use alternative_input() to specify clobbers. */
+    alternative_input("", "DO_OVERWRITE_RSB", X86_BUG_IBPB_NO_RET,
+                      : "rax", "rcx");
+}
+
 extern int8_t opt_ibpb_ctxt_switch;
 extern bool opt_ssbd;
 extern int8_t opt_eager_fpu;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13


From xen-changelog-bounces@lists.xenproject.org Wed Nov 09 15:00:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 09 Nov 2022 15:00:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441060.695318 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osmYm-0005uE-SM; Wed, 09 Nov 2022 15:00:12 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441060.695318; Wed, 09 Nov 2022 15:00:12 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osmYm-0005u6-P8; Wed, 09 Nov 2022 15:00:12 +0000
Received: by outflank-mailman (input) for mailman id 441060;
 Wed, 09 Nov 2022 15:00:11 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osmYl-0005ty-QI
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 15:00:11 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osmYl-0008C8-PX
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 15:00:11 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osmYl-0007FG-OR
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 15:00:11 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=HgCKvytSLD3b6Bcw9Oxu0eH8/wc3UHKHXTAK9IxuYHY=; b=vUlRW0ryE9V+sBr7R38w0rysCt
	Y/DO+TSmjGEDlIsbHjznnQpcmHsLOD9Beqr4GyKYdLFHSzs9MbrjCz7I8Yx7gaRrXjbQ3oE3d5cHA
	EG20JdS9pVagrdj0bGZ7JzJKQPmXJ9SBbKWtPuOXuJyczi1XT8UUVYZgK4zKVsWAphqA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
Message-Id: <E1osmYl-0007FG-OR@xenbits.xenproject.org>
Date: Wed, 09 Nov 2022 15:00:11 +0000

commit 46040a5fe68831530b8ffdea7d264e52ae316c87
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Fri Nov 4 13:23:22 2022 +0000

    x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
    
    Introduce spec_ctrl_new_guest_context() to encapsulate all logic pertaining to
    using MSR_PRED_CMD for a new guest context, even if it only has one user
    presently.
    
    Introduce X86_BUG_IBPB_NO_RET, and use it extend spec_ctrl_new_guest_context()
    with a manual fixup for hardware which mis-implements IBPB.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 2b27967fb89d7904a1571a2fb963b1c9cac548db)
---
 xen/arch/x86/asm-macros.c         |  1 +
 xen/arch/x86/domain.c             |  2 +-
 xen/arch/x86/spec_ctrl.c          |  8 ++++++++
 xen/include/asm-x86/cpufeatures.h |  1 +
 xen/include/asm-x86/spec_ctrl.h   | 22 ++++++++++++++++++++++
 5 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/asm-macros.c b/xen/arch/x86/asm-macros.c
index b963d56a56..8c585697b9 100644
--- a/xen/arch/x86/asm-macros.c
+++ b/xen/arch/x86/asm-macros.c
@@ -1 +1,2 @@
 #include <asm/alternative-asm.h>
+#include <asm/spec_ctrl_asm.h>
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 4fb78d38e7..b3774af1a5 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1832,7 +1832,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
              */
             if ( *last_id != next_id )
             {
-                wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+                spec_ctrl_new_guest_context();
                 *last_id = next_id;
             }
         }
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 679fbac57e..c650e07b06 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -776,6 +776,14 @@ static void __init ibpb_calculations(void)
         return;
     }
 
+    /*
+     * AMD/Hygon CPUs to date (June 2022) don't flush the the RAS.  Future
+     * CPUs are expected to enumerate IBPB_RET when this has been fixed.
+     * Until then, cover the difference with the software sequence.
+     */
+    if ( boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_IBPB_RET) )
+        setup_force_cpu_cap(X86_BUG_IBPB_NO_RET);
+
     /*
      * IBPB-on-entry mitigations for Branch Type Confusion.
      *
diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h
index b233e5835f..bdb119a34c 100644
--- a/xen/include/asm-x86/cpufeatures.h
+++ b/xen/include/asm-x86/cpufeatures.h
@@ -48,6 +48,7 @@ XEN_CPUFEATURE(IBPB_ENTRY_HVM,    X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for
 
 #define X86_BUG_FPU_PTRS          X86_BUG( 0) /* (F)X{SAVE,RSTOR} doesn't save/restore FOP/FIP/FDP. */
 #define X86_BUG_CLFLUSH_MFENCE    X86_BUG( 2) /* MFENCE needed to serialise CLFLUSH */
+#define X86_BUG_IBPB_NO_RET       X86_BUG( 3) /* IBPB doesn't flush the RSB/RAS */
 
 /* Total number of capability words, inc synth and bug words. */
 #define NCAPINTS (FSCAPINTS + X86_NR_SYNTH + X86_NR_BUG) /* N 32-bit words worth of info */
diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h
index 33e845991b..e400ff2273 100644
--- a/xen/include/asm-x86/spec_ctrl.h
+++ b/xen/include/asm-x86/spec_ctrl.h
@@ -65,6 +65,28 @@
 void init_speculation_mitigations(void);
 void spec_ctrl_init_domain(struct domain *d);
 
+/*
+ * Switch to a new guest prediction context.
+ *
+ * This flushes all indirect branch predictors (BTB, RSB/RAS), so guest code
+ * which has previously run on this CPU can't attack subsequent guest code.
+ *
+ * As this flushes the RSB/RAS, it destroys the predictions of the calling
+ * context.  For best performace, arrange for this to be used when we're going
+ * to jump out of the current context, e.g. with reset_stack_and_jump().
+ *
+ * For hardware which mis-implements IBPB, fix up by flushing the RSB/RAS
+ * manually.
+ */
+static always_inline void spec_ctrl_new_guest_context(void)
+{
+    wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+
+    /* (ab)use alternative_input() to specify clobbers. */
+    alternative_input("", "DO_OVERWRITE_RSB", X86_BUG_IBPB_NO_RET,
+                      : "rax", "rcx");
+}
+
 extern int8_t opt_ibpb_ctxt_switch;
 extern bool opt_ssbd;
 extern int8_t opt_eager_fpu;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 09 15:00:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 09 Nov 2022 15:00:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441059.695316 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osmYc-0005O1-RY; Wed, 09 Nov 2022 15:00:02 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441059.695316; Wed, 09 Nov 2022 15:00:02 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osmYc-0005NR-Na; Wed, 09 Nov 2022 15:00:02 +0000
Received: by outflank-mailman (input) for mailman id 441059;
 Wed, 09 Nov 2022 15:00:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osmYb-0005CT-V2
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 15:00:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osmYb-00089p-M0
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 15:00:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osmYb-0007DU-Ku
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 15:00:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=qDnkBEUkmHoyxaeHcpc2kentciSzvGxz+l1wsGpJpbc=; b=oseYjbxNMyIPybcEcxFNErdHDj
	RzjQHrwO1Kp3oRIpWjDfckMclUqias0qM9yaPI5PRf/21LSYT2tc4uUagEOzTjXLO+YlX3BIjwk0C
	xr+HfBEJ4KOA/YL+oq6NS0mM6S46IgIx975A8JGgjxqqIjufg3Hd8i391tDi7BXul4vU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.14] x86/spec-ctrl: Enumeration for IBPB_RET
Message-Id: <E1osmYb-0007DU-Ku@xenbits.xenproject.org>
Date: Wed, 09 Nov 2022 15:00:01 +0000

commit 013a27047ca63834236bfd38ba4d3a8b9d828781
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Fri Nov 4 13:23:21 2022 +0000

    x86/spec-ctrl: Enumeration for IBPB_RET
    
    The IBPB_RET bit indicates that the CPU's implementation of MSR_PRED_CMD.IBPB
    does flush the RSB/RAS too.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 24496558e650535bdbd22cc04731e82276cd1b3f)
---
 tools/libxl/libxl_cpuid.c                   | 1 +
 tools/misc/xen-cpuid.c                      | 1 +
 xen/arch/x86/spec_ctrl.c                    | 5 +++--
 xen/include/public/arch-x86/cpufeatureset.h | 1 +
 4 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c
index 25576b4d99..1b7626f7d4 100644
--- a/tools/libxl/libxl_cpuid.c
+++ b/tools/libxl/libxl_cpuid.c
@@ -281,6 +281,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
         {"ssb-no",       0x80000008, NA, CPUID_REG_EBX, 26,  1},
         {"psfd",         0x80000008, NA, CPUID_REG_EBX, 28,  1},
         {"btc-no",       0x80000008, NA, CPUID_REG_EBX, 29,  1},
+        {"ibpb-ret",     0x80000008, NA, CPUID_REG_EBX, 30,  1},
 
         {"nc",           0x80000008, NA, CPUID_REG_ECX,  0,  8},
         {"apicidsize",   0x80000008, NA, CPUID_REG_ECX, 12,  4},
diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c
index e5208cfa45..7771da4953 100644
--- a/tools/misc/xen-cpuid.c
+++ b/tools/misc/xen-cpuid.c
@@ -158,6 +158,7 @@ static const char *const str_e8b[32] =
     [24] = "amd-ssbd",         [25] = "virt-ssbd",
     [26] = "ssb-no",
     [28] = "psfd",             [29] = "btc-no",
+    [30] = "ibpb-ret",
 };
 
 static const char *const str_7d0[32] =
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 563519ce0e..679fbac57e 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -419,7 +419,7 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
      * Hardware read-only information, stating immunity to certain issues, or
      * suggestions of which mitigation to use.
      */
-    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
            (caps & ARCH_CAPS_RDCL_NO)                        ? " RDCL_NO"        : "",
            (caps & ARCH_CAPS_IBRS_ALL)                       ? " IBRS_ALL"       : "",
            (caps & ARCH_CAPS_RSBA)                           ? " RSBA"           : "",
@@ -435,7 +435,8 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
            (e8b  & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS))   ? " STIBP_ALWAYS"   : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_FAST))      ? " IBRS_FAST"      : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_SAME_MODE)) ? " IBRS_SAME_MODE" : "",
-           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "");
+           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "",
+           (e8b  & cpufeat_mask(X86_FEATURE_IBPB_RET))       ? " IBPB_RET"       : "");
 
     /* Hardware features which need driving to mitigate issues. */
     printk("  Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s\n",
diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h
index 746a75200a..e536ab42b3 100644
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -265,6 +265,7 @@ XEN_CPUFEATURE(VIRT_SSBD,     8*32+25) /*   MSR_VIRT_SPEC_CTRL.SSBD */
 XEN_CPUFEATURE(SSB_NO,        8*32+26) /*A  Hardware not vulnerable to SSB */
 XEN_CPUFEATURE(PSFD,          8*32+28) /*S  MSR_SPEC_CTRL.PSFD */
 XEN_CPUFEATURE(BTC_NO,        8*32+29) /*A  Hardware not vulnerable to Branch Type Confusion */
+XEN_CPUFEATURE(IBPB_RET,      8*32+30) /*A  IBPB clears RSB/RAS too. */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0.edx, word 9 */
 XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A  AVX512 Neural Network Instructions */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14


From xen-changelog-bounces@lists.xenproject.org Wed Nov 09 17:22:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 09 Nov 2022 17:22:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441092.695372 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osom4-0001GW-0i; Wed, 09 Nov 2022 17:22:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441092.695372; Wed, 09 Nov 2022 17:22:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osom3-0001GO-UI; Wed, 09 Nov 2022 17:22:03 +0000
Received: by outflank-mailman (input) for mailman id 441092;
 Wed, 09 Nov 2022 17:22:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osom2-0001GI-5g
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 17:22:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osom2-0003TZ-39
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 17:22:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osom2-0000xf-2B
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 17:22:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=9s1opKcmzecPniB7KQOGekPAzm3w97ctiimHy8p8wl8=; b=5FLy4VctncAGW98EWZYbSvLOCN
	+48M9KciYmTR65sTv6NfMkKFevwcchrQU5QVwKk/eZS6tmRCDroAuRtU7ip/JWebfSWS5StsLOclZ
	CHN2aHPREanSdRNS9p5lQtteWGldm4AVKt7SjdSu+GY9b58jPpaOwUJA1ZpMQvQQekDY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] x86/spec-ctrl: Enumeration for IBPB_RET
Message-Id: <E1osom2-0000xf-2B@xenbits.xenproject.org>
Date: Wed, 09 Nov 2022 17:22:02 +0000

commit b1a1df345aaf359f305d6d041e571929c9252645
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Fri Nov 4 13:20:27 2022 +0000

    x86/spec-ctrl: Enumeration for IBPB_RET
    
    The IBPB_RET bit indicates that the CPU's implementation of MSR_PRED_CMD.IBPB
    does flush the RSB/RAS too.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 24496558e650535bdbd22cc04731e82276cd1b3f)
---
 tools/libs/light/libxl_cpuid.c              | 1 +
 tools/misc/xen-cpuid.c                      | 1 +
 xen/arch/x86/spec_ctrl.c                    | 5 +++--
 xen/include/public/arch-x86/cpufeatureset.h | 1 +
 4 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/libs/light/libxl_cpuid.c b/tools/libs/light/libxl_cpuid.c
index bf6fdee360..691d5c6b2a 100644
--- a/tools/libs/light/libxl_cpuid.c
+++ b/tools/libs/light/libxl_cpuid.c
@@ -289,6 +289,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
         {"ssb-no",       0x80000008, NA, CPUID_REG_EBX, 26,  1},
         {"psfd",         0x80000008, NA, CPUID_REG_EBX, 28,  1},
         {"btc-no",       0x80000008, NA, CPUID_REG_EBX, 29,  1},
+        {"ibpb-ret",     0x80000008, NA, CPUID_REG_EBX, 30,  1},
 
         {"nc",           0x80000008, NA, CPUID_REG_ECX,  0,  8},
         {"apicidsize",   0x80000008, NA, CPUID_REG_ECX, 12,  4},
diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c
index fe22f5f5b6..cd094427dd 100644
--- a/tools/misc/xen-cpuid.c
+++ b/tools/misc/xen-cpuid.c
@@ -159,6 +159,7 @@ static const char *const str_e8b[32] =
     [24] = "amd-ssbd",         [25] = "virt-ssbd",
     [26] = "ssb-no",
     [28] = "psfd",             [29] = "btc-no",
+    [30] = "ibpb-ret",
 };
 
 static const char *const str_7d0[32] =
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 0f4bad3d3a..16a562d3a1 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -419,7 +419,7 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
      * Hardware read-only information, stating immunity to certain issues, or
      * suggestions of which mitigation to use.
      */
-    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
            (caps & ARCH_CAPS_RDCL_NO)                        ? " RDCL_NO"        : "",
            (caps & ARCH_CAPS_IBRS_ALL)                       ? " IBRS_ALL"       : "",
            (caps & ARCH_CAPS_RSBA)                           ? " RSBA"           : "",
@@ -436,7 +436,8 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
            (e8b  & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS))   ? " STIBP_ALWAYS"   : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_FAST))      ? " IBRS_FAST"      : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_SAME_MODE)) ? " IBRS_SAME_MODE" : "",
-           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "");
+           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "",
+           (e8b  & cpufeat_mask(X86_FEATURE_IBPB_RET))       ? " IBPB_RET"       : "");
 
     /* Hardware features which need driving to mitigate issues. */
     printk("  Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s\n",
diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h
index e7b8167800..e073122140 100644
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -267,6 +267,7 @@ XEN_CPUFEATURE(VIRT_SSBD,     8*32+25) /*   MSR_VIRT_SPEC_CTRL.SSBD */
 XEN_CPUFEATURE(SSB_NO,        8*32+26) /*A  Hardware not vulnerable to SSB */
 XEN_CPUFEATURE(PSFD,          8*32+28) /*S  MSR_SPEC_CTRL.PSFD */
 XEN_CPUFEATURE(BTC_NO,        8*32+29) /*A  Hardware not vulnerable to Branch Type Confusion */
+XEN_CPUFEATURE(IBPB_RET,      8*32+30) /*A  IBPB clears RSB/RAS too. */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0.edx, word 9 */
 XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A  AVX512 Neural Network Instructions */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 09 17:22:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 09 Nov 2022 17:22:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441093.695376 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osomD-0001I5-2i; Wed, 09 Nov 2022 17:22:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441093.695376; Wed, 09 Nov 2022 17:22:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1osomC-0001Hx-Vm; Wed, 09 Nov 2022 17:22:12 +0000
Received: by outflank-mailman (input) for mailman id 441093;
 Wed, 09 Nov 2022 17:22:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osomC-0001Hp-7D
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 17:22:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osomC-0003Td-6V
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 17:22:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1osomC-0000zg-5Z
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 17:22:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=+pFlMWaxkG8efMkFTuGA0Os1/J7HiSGlI8+0SLWsbWw=; b=uxoy34eIp2flY8R7Z4zARc99eU
	RP8RWlbwoTdmNu8pK4mXPlRDeXJLDyDTCkxxJHBskZdJcMKq7l2PujZLYxV/iUUQ3NVx2tmw1Zlj8
	EHh0eX1uUyn1GzhyLFQTRf9HLp19dsliuHzXKzBNkfyuPciFGycFuw4T2aqVmVH9M+hY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
Message-Id: <E1osomC-0000zg-5Z@xenbits.xenproject.org>
Date: Wed, 09 Nov 2022 17:22:12 +0000

commit c1e196ab490b47ce42037c2fef8184a19d96922b
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Fri Nov 4 13:20:27 2022 +0000

    x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
    
    Introduce spec_ctrl_new_guest_context() to encapsulate all logic pertaining to
    using MSR_PRED_CMD for a new guest context, even if it only has one user
    presently.
    
    Introduce X86_BUG_IBPB_NO_RET, and use it extend spec_ctrl_new_guest_context()
    with a manual fixup for hardware which mis-implements IBPB.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 2b27967fb89d7904a1571a2fb963b1c9cac548db)
---
 xen/arch/x86/asm-macros.c         |  1 +
 xen/arch/x86/domain.c             |  2 +-
 xen/arch/x86/spec_ctrl.c          |  8 ++++++++
 xen/include/asm-x86/cpufeatures.h |  1 +
 xen/include/asm-x86/spec_ctrl.h   | 22 ++++++++++++++++++++++
 5 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/asm-macros.c b/xen/arch/x86/asm-macros.c
index 7e536b0d82..891d86c765 100644
--- a/xen/arch/x86/asm-macros.c
+++ b/xen/arch/x86/asm-macros.c
@@ -1,2 +1,3 @@
 #include <asm/asm-defns.h>
 #include <asm/alternative-asm.h>
+#include <asm/spec_ctrl_asm.h>
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 3fab2364be..3080cde62b 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -2092,7 +2092,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
              */
             if ( *last_id != next_id )
             {
-                wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+                spec_ctrl_new_guest_context();
                 *last_id = next_id;
             }
         }
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 16a562d3a1..90d86fe5cb 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -804,6 +804,14 @@ static void __init ibpb_calculations(void)
         return;
     }
 
+    /*
+     * AMD/Hygon CPUs to date (June 2022) don't flush the the RAS.  Future
+     * CPUs are expected to enumerate IBPB_RET when this has been fixed.
+     * Until then, cover the difference with the software sequence.
+     */
+    if ( boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_IBPB_RET) )
+        setup_force_cpu_cap(X86_BUG_IBPB_NO_RET);
+
     /*
      * IBPB-on-entry mitigations for Branch Type Confusion.
      *
diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h
index 672c9ee22b..ecc1bb0950 100644
--- a/xen/include/asm-x86/cpufeatures.h
+++ b/xen/include/asm-x86/cpufeatures.h
@@ -49,6 +49,7 @@ XEN_CPUFEATURE(IBPB_ENTRY_HVM,    X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for
 #define X86_BUG_FPU_PTRS          X86_BUG( 0) /* (F)X{SAVE,RSTOR} doesn't save/restore FOP/FIP/FDP. */
 #define X86_BUG_NULL_SEG          X86_BUG( 1) /* NULL-ing a selector preserves the base and limit. */
 #define X86_BUG_CLFLUSH_MFENCE    X86_BUG( 2) /* MFENCE needed to serialise CLFLUSH */
+#define X86_BUG_IBPB_NO_RET       X86_BUG( 3) /* IBPB doesn't flush the RSB/RAS */
 
 /* Total number of capability words, inc synth and bug words. */
 #define NCAPINTS (FSCAPINTS + X86_NR_SYNTH + X86_NR_BUG) /* N 32-bit words worth of info */
diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h
index 9403b81dc7..6a77c39378 100644
--- a/xen/include/asm-x86/spec_ctrl.h
+++ b/xen/include/asm-x86/spec_ctrl.h
@@ -65,6 +65,28 @@
 void init_speculation_mitigations(void);
 void spec_ctrl_init_domain(struct domain *d);
 
+/*
+ * Switch to a new guest prediction context.
+ *
+ * This flushes all indirect branch predictors (BTB, RSB/RAS), so guest code
+ * which has previously run on this CPU can't attack subsequent guest code.
+ *
+ * As this flushes the RSB/RAS, it destroys the predictions of the calling
+ * context.  For best performace, arrange for this to be used when we're going
+ * to jump out of the current context, e.g. with reset_stack_and_jump().
+ *
+ * For hardware which mis-implements IBPB, fix up by flushing the RSB/RAS
+ * manually.
+ */
+static always_inline void spec_ctrl_new_guest_context(void)
+{
+    wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+
+    /* (ab)use alternative_input() to specify clobbers. */
+    alternative_input("", "DO_OVERWRITE_RSB", X86_BUG_IBPB_NO_RET,
+                      : "rax", "rcx");
+}
+
 extern int8_t opt_ibpb_ctxt_switch;
 extern bool opt_ssbd;
 extern int8_t opt_eager_fpu;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Wed Nov 09 22:33:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 09 Nov 2022 22:33:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441151.695474 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ostd2-0002h7-2X; Wed, 09 Nov 2022 22:33:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441151.695474; Wed, 09 Nov 2022 22:33:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ostd1-0002gx-VK; Wed, 09 Nov 2022 22:33:03 +0000
Received: by outflank-mailman (input) for mailman id 441151;
 Wed, 09 Nov 2022 22:33:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ostd0-0002gY-Ca
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 22:33:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ostd0-0001u8-Bj
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 22:33:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ostd0-00043k-Aj
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 22:33:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=1wq79QB2mhwXha3xs3uvBiLUeBkWoFNCRwJ0vcgDhqQ=; b=QxhbHnyeuCJnPW0oTxNgCx1mcZ
	u7ic/LO/HcBvRids781WfX0JYggpodnHeqeBON8yVXzgoy13N1yjrxGeTo1rtlFdfnYux3dI6P1CZ
	vp5bRkJ612QqMLKYEbHUFhlxAWL1t2Rw+8Z2dLFI9kKhYjTquMMHZzlL+/8HIl8+8Dpc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] x86/spec-ctrl: Enumeration for IBPB_RET
Message-Id: <E1ostd0-00043k-Aj@xenbits.xenproject.org>
Date: Wed, 09 Nov 2022 22:33:02 +0000

commit 24496558e650535bdbd22cc04731e82276cd1b3f
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 8 17:26:08 2022 +0000

    x86/spec-ctrl: Enumeration for IBPB_RET
    
    The IBPB_RET bit indicates that the CPU's implementation of MSR_PRED_CMD.IBPB
    does flush the RSB/RAS too.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
---
 tools/libs/light/libxl_cpuid.c              | 1 +
 tools/misc/xen-cpuid.c                      | 1 +
 xen/arch/x86/spec_ctrl.c                    | 5 +++--
 xen/include/public/arch-x86/cpufeatureset.h | 1 +
 4 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/libs/light/libxl_cpuid.c b/tools/libs/light/libxl_cpuid.c
index d5a9b35774..2aa23225f4 100644
--- a/tools/libs/light/libxl_cpuid.c
+++ b/tools/libs/light/libxl_cpuid.c
@@ -291,6 +291,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
         {"ssb-no",       0x80000008, NA, CPUID_REG_EBX, 26,  1},
         {"psfd",         0x80000008, NA, CPUID_REG_EBX, 28,  1},
         {"btc-no",       0x80000008, NA, CPUID_REG_EBX, 29,  1},
+        {"ibpb-ret",     0x80000008, NA, CPUID_REG_EBX, 30,  1},
 
         {"nc",           0x80000008, NA, CPUID_REG_ECX,  0,  8},
         {"apicidsize",   0x80000008, NA, CPUID_REG_ECX, 12,  4},
diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c
index 390ac1dafe..d5833e9ce8 100644
--- a/tools/misc/xen-cpuid.c
+++ b/tools/misc/xen-cpuid.c
@@ -161,6 +161,7 @@ static const char *const str_e8b[32] =
     [24] = "amd-ssbd",         [25] = "virt-ssbd",
     [26] = "ssb-no",
     [28] = "psfd",             [29] = "btc-no",
+    [30] = "ibpb-ret",
 };
 
 static const char *const str_7d0[32] =
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 4e53056624..0c3503c9cd 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -420,7 +420,7 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
      * Hardware read-only information, stating immunity to certain issues, or
      * suggestions of which mitigation to use.
      */
-    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
            (caps & ARCH_CAPS_RDCL_NO)                        ? " RDCL_NO"        : "",
            (caps & ARCH_CAPS_IBRS_ALL)                       ? " IBRS_ALL"       : "",
            (caps & ARCH_CAPS_RSBA)                           ? " RSBA"           : "",
@@ -437,7 +437,8 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
            (e8b  & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS))   ? " STIBP_ALWAYS"   : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_FAST))      ? " IBRS_FAST"      : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_SAME_MODE)) ? " IBRS_SAME_MODE" : "",
-           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "");
+           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "",
+           (e8b  & cpufeat_mask(X86_FEATURE_IBPB_RET))       ? " IBPB_RET"       : "");
 
     /* Hardware features which need driving to mitigate issues. */
     printk("  Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s\n",
diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h
index 42f48a8ae2..02675e9c75 100644
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -269,6 +269,7 @@ XEN_CPUFEATURE(VIRT_SSBD,     8*32+25) /*!  MSR_VIRT_SPEC_CTRL.SSBD */
 XEN_CPUFEATURE(SSB_NO,        8*32+26) /*A  Hardware not vulnerable to SSB */
 XEN_CPUFEATURE(PSFD,          8*32+28) /*S  MSR_SPEC_CTRL.PSFD */
 XEN_CPUFEATURE(BTC_NO,        8*32+29) /*A  Hardware not vulnerable to Branch Type Confusion */
+XEN_CPUFEATURE(IBPB_RET,      8*32+30) /*A  IBPB clears RSB/RAS too. */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0.edx, word 9 */
 XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A  AVX512 Neural Network Instructions */
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 09 22:33:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 09 Nov 2022 22:33:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441152.695479 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ostdC-0002jd-4y; Wed, 09 Nov 2022 22:33:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441152.695479; Wed, 09 Nov 2022 22:33:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ostdC-0002jV-29; Wed, 09 Nov 2022 22:33:14 +0000
Received: by outflank-mailman (input) for mailman id 441152;
 Wed, 09 Nov 2022 22:33:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ostdA-0002jE-Fm
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 22:33:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ostdA-0001uC-F0
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 22:33:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ostdA-00044A-E0
 for xen-changelog@lists.xenproject.org; Wed, 09 Nov 2022 22:33:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=u4nKyZs1pNRmRf4u7v0mP9gfOBCNCubJcWdoeQWrIoY=; b=TMgaB0JKYHhGTGstcaB+9Gfh7t
	ZYd8dgsDzJTMNqUQZ8IgGoh5RoYIbjPF0NQWavzVV94/T2GVD8ACVGiPYFUN+GbmXfU45yt8HHpKH
	7NX9PkZwTfqqsIObcxTzeJL6rlrc53CTQwlHbkGRG6ydggn3uQS1cRYhmirQ3ccogCdQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
Message-Id: <E1ostdA-00044A-E0@xenbits.xenproject.org>
Date: Wed, 09 Nov 2022 22:33:12 +0000

commit 2b27967fb89d7904a1571a2fb963b1c9cac548db
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Tue Nov 8 17:26:08 2022 +0000

    x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
    
    Introduce spec_ctrl_new_guest_context() to encapsulate all logic pertaining to
    using MSR_PRED_CMD for a new guest context, even if it only has one user
    presently.
    
    Introduce X86_BUG_IBPB_NO_RET, and use it extend spec_ctrl_new_guest_context()
    with a manual fixup for hardware which mis-implements IBPB.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/asm-macros.c              |  1 +
 xen/arch/x86/domain.c                  |  2 +-
 xen/arch/x86/include/asm/cpufeatures.h |  1 +
 xen/arch/x86/include/asm/spec_ctrl.h   | 22 ++++++++++++++++++++++
 xen/arch/x86/spec_ctrl.c               |  8 ++++++++
 5 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/asm-macros.c b/xen/arch/x86/asm-macros.c
index 7e536b0d82..891d86c765 100644
--- a/xen/arch/x86/asm-macros.c
+++ b/xen/arch/x86/asm-macros.c
@@ -1,2 +1,3 @@
 #include <asm/asm-defns.h>
 #include <asm/alternative-asm.h>
+#include <asm/spec_ctrl_asm.h>
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index ce82c502bb..79107dac69 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -2117,7 +2117,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
              */
             if ( *last_id != next_id )
             {
-                wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+                spec_ctrl_new_guest_context();
                 *last_id = next_id;
             }
         }
diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h
index 3895de4faf..c68ced1b82 100644
--- a/xen/arch/x86/include/asm/cpufeatures.h
+++ b/xen/arch/x86/include/asm/cpufeatures.h
@@ -49,6 +49,7 @@ XEN_CPUFEATURE(IBPB_ENTRY_HVM,    X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for
 #define X86_BUG_FPU_PTRS          X86_BUG( 0) /* (F)X{SAVE,RSTOR} doesn't save/restore FOP/FIP/FDP. */
 #define X86_BUG_NULL_SEG          X86_BUG( 1) /* NULL-ing a selector preserves the base and limit. */
 #define X86_BUG_CLFLUSH_MFENCE    X86_BUG( 2) /* MFENCE needed to serialise CLFLUSH */
+#define X86_BUG_IBPB_NO_RET       X86_BUG( 3) /* IBPB doesn't flush the RSB/RAS */
 
 /* Total number of capability words, inc synth and bug words. */
 #define NCAPINTS (FSCAPINTS + X86_NR_SYNTH + X86_NR_BUG) /* N 32-bit words worth of info */
diff --git a/xen/arch/x86/include/asm/spec_ctrl.h b/xen/arch/x86/include/asm/spec_ctrl.h
index 9403b81dc7..6a77c39378 100644
--- a/xen/arch/x86/include/asm/spec_ctrl.h
+++ b/xen/arch/x86/include/asm/spec_ctrl.h
@@ -65,6 +65,28 @@
 void init_speculation_mitigations(void);
 void spec_ctrl_init_domain(struct domain *d);
 
+/*
+ * Switch to a new guest prediction context.
+ *
+ * This flushes all indirect branch predictors (BTB, RSB/RAS), so guest code
+ * which has previously run on this CPU can't attack subsequent guest code.
+ *
+ * As this flushes the RSB/RAS, it destroys the predictions of the calling
+ * context.  For best performace, arrange for this to be used when we're going
+ * to jump out of the current context, e.g. with reset_stack_and_jump().
+ *
+ * For hardware which mis-implements IBPB, fix up by flushing the RSB/RAS
+ * manually.
+ */
+static always_inline void spec_ctrl_new_guest_context(void)
+{
+    wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+
+    /* (ab)use alternative_input() to specify clobbers. */
+    alternative_input("", "DO_OVERWRITE_RSB", X86_BUG_IBPB_NO_RET,
+                      : "rax", "rcx");
+}
+
 extern int8_t opt_ibpb_ctxt_switch;
 extern bool opt_ssbd;
 extern int8_t opt_eager_fpu;
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 0c3503c9cd..a0835143e3 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -810,6 +810,14 @@ static void __init ibpb_calculations(void)
         return;
     }
 
+    /*
+     * AMD/Hygon CPUs to date (June 2022) don't flush the the RAS.  Future
+     * CPUs are expected to enumerate IBPB_RET when this has been fixed.
+     * Until then, cover the difference with the software sequence.
+     */
+    if ( boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_IBPB_RET) )
+        setup_force_cpu_cap(X86_BUG_IBPB_NO_RET);
+
     /*
      * IBPB-on-entry mitigations for Branch Type Confusion.
      *
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 10 11:11:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 10 Nov 2022 11:11:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441770.695823 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot5SZ-0002gg-L9; Thu, 10 Nov 2022 11:11:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441770.695823; Thu, 10 Nov 2022 11:11:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot5SZ-0002gY-IE; Thu, 10 Nov 2022 11:11:03 +0000
Received: by outflank-mailman (input) for mailman id 441770;
 Thu, 10 Nov 2022 11:11:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5SY-0002gS-4O
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5SY-00037l-2W
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5SX-0001Yz-Vy
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=e3nGb/S4nrCXVnY7l5GYA1ZcLC/qUCN73jINS8pLUPw=; b=UmzU/YyjGAEOC3gCn5UnzcHJWp
	Ia2UXmP2wbEr3OLmS08IzuaYqf8p0y/8AOfHPb8lKO39DSH6n84LdQHhHmk7ISBLv3DyoXJyvGIUp
	5Kzq29tK/8FYv678kyxcIvp9UdEJjSTYf2Przy/oNvJxQrpbpQSDfGf82LSHwyiOXJ2Q=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] x86/spec-ctrl: Enumeration for IBPB_RET
Message-Id: <E1ot5SX-0001Yz-Vy@xenbits.xenproject.org>
Date: Thu, 10 Nov 2022 11:11:01 +0000

commit 07be0fe497349ed423c5201bdc410b6281ebf04f
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Fri Nov 4 13:22:03 2022 +0000

    x86/spec-ctrl: Enumeration for IBPB_RET
    
    The IBPB_RET bit indicates that the CPU's implementation of MSR_PRED_CMD.IBPB
    does flush the RSB/RAS too.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 24496558e650535bdbd22cc04731e82276cd1b3f)
---
 tools/libs/light/libxl_cpuid.c              | 1 +
 tools/misc/xen-cpuid.c                      | 1 +
 xen/arch/x86/spec_ctrl.c                    | 5 +++--
 xen/include/public/arch-x86/cpufeatureset.h | 1 +
 4 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/libs/light/libxl_cpuid.c b/tools/libs/light/libxl_cpuid.c
index 2632efc6ad..4cc2f211b8 100644
--- a/tools/libs/light/libxl_cpuid.c
+++ b/tools/libs/light/libxl_cpuid.c
@@ -284,6 +284,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
         {"ssb-no",       0x80000008, NA, CPUID_REG_EBX, 26,  1},
         {"psfd",         0x80000008, NA, CPUID_REG_EBX, 28,  1},
         {"btc-no",       0x80000008, NA, CPUID_REG_EBX, 29,  1},
+        {"ibpb-ret",     0x80000008, NA, CPUID_REG_EBX, 30,  1},
 
         {"nc",           0x80000008, NA, CPUID_REG_ECX,  0,  8},
         {"apicidsize",   0x80000008, NA, CPUID_REG_ECX, 12,  4},
diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c
index e83bc4793d..5c944c24fe 100644
--- a/tools/misc/xen-cpuid.c
+++ b/tools/misc/xen-cpuid.c
@@ -158,6 +158,7 @@ static const char *const str_e8b[32] =
     [24] = "amd-ssbd",         [25] = "virt-ssbd",
     [26] = "ssb-no",
     [28] = "psfd",             [29] = "btc-no",
+    [30] = "ibpb-ret",
 };
 
 static const char *const str_7d0[32] =
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 3ff602bd02..459c64d139 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -419,7 +419,7 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
      * Hardware read-only information, stating immunity to certain issues, or
      * suggestions of which mitigation to use.
      */
-    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+    printk("  Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
            (caps & ARCH_CAPS_RDCL_NO)                        ? " RDCL_NO"        : "",
            (caps & ARCH_CAPS_IBRS_ALL)                       ? " IBRS_ALL"       : "",
            (caps & ARCH_CAPS_RSBA)                           ? " RSBA"           : "",
@@ -436,7 +436,8 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
            (e8b  & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS))   ? " STIBP_ALWAYS"   : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_FAST))      ? " IBRS_FAST"      : "",
            (e8b  & cpufeat_mask(X86_FEATURE_IBRS_SAME_MODE)) ? " IBRS_SAME_MODE" : "",
-           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "");
+           (e8b  & cpufeat_mask(X86_FEATURE_BTC_NO))         ? " BTC_NO"         : "",
+           (e8b  & cpufeat_mask(X86_FEATURE_IBPB_RET))       ? " IBPB_RET"       : "");
 
     /* Hardware features which need driving to mitigate issues. */
     printk("  Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s\n",
diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h
index 1bbc7da4b5..41a358d575 100644
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -266,6 +266,7 @@ XEN_CPUFEATURE(VIRT_SSBD,     8*32+25) /*   MSR_VIRT_SPEC_CTRL.SSBD */
 XEN_CPUFEATURE(SSB_NO,        8*32+26) /*A  Hardware not vulnerable to SSB */
 XEN_CPUFEATURE(PSFD,          8*32+28) /*S  MSR_SPEC_CTRL.PSFD */
 XEN_CPUFEATURE(BTC_NO,        8*32+29) /*A  Hardware not vulnerable to Branch Type Confusion */
+XEN_CPUFEATURE(IBPB_RET,      8*32+30) /*A  IBPB clears RSB/RAS too. */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0.edx, word 9 */
 XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A  AVX512 Neural Network Instructions */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Thu Nov 10 11:11:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 10 Nov 2022 11:11:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441771.695826 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot5Sj-0002ik-MX; Thu, 10 Nov 2022 11:11:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441771.695826; Thu, 10 Nov 2022 11:11:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot5Sj-0002ic-Jl; Thu, 10 Nov 2022 11:11:13 +0000
Received: by outflank-mailman (input) for mailman id 441771;
 Thu, 10 Nov 2022 11:11:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5Si-0002iT-7t
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5Si-00037r-6J
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5Si-0001ZT-53
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=eo9khxQ8YawNGVfKPPgkY7E8ydtj2ymWgFeSJLqk3UY=; b=Txp6kEalyy5G2en80kU95MaZuA
	Wy9YKKmTJq0zo3YIfO7FvWVzasvEOX/xD2/FbNN2B/CrVJ2jMi54KKb7h1IfF2lK2WUFy51rLdF6j
	rGxZSGNuFk/3+jFU64FfWKSZmJ8lOHze6RnFsVqD2MlY7g+4TRFBqLKLiUsFP7nPzYQQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
Message-Id: <E1ot5Si-0001ZT-53@xenbits.xenproject.org>
Date: Thu, 10 Nov 2022 11:11:12 +0000

commit 32445f23fea6a533fc1d7ade5871246d75210bf1
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Jun 14 16:18:36 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Fri Nov 4 13:22:04 2022 +0000

    x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS
    
    Introduce spec_ctrl_new_guest_context() to encapsulate all logic pertaining to
    using MSR_PRED_CMD for a new guest context, even if it only has one user
    presently.
    
    Introduce X86_BUG_IBPB_NO_RET, and use it extend spec_ctrl_new_guest_context()
    with a manual fixup for hardware which mis-implements IBPB.
    
    This is part of XSA-422 / CVE-2022-23824.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    (cherry picked from commit 2b27967fb89d7904a1571a2fb963b1c9cac548db)
---
 xen/arch/x86/asm-macros.c         |  1 +
 xen/arch/x86/domain.c             |  2 +-
 xen/arch/x86/spec_ctrl.c          |  8 ++++++++
 xen/include/asm-x86/cpufeatures.h |  1 +
 xen/include/asm-x86/spec_ctrl.h   | 22 ++++++++++++++++++++++
 5 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/asm-macros.c b/xen/arch/x86/asm-macros.c
index 7e536b0d82..891d86c765 100644
--- a/xen/arch/x86/asm-macros.c
+++ b/xen/arch/x86/asm-macros.c
@@ -1,2 +1,3 @@
 #include <asm/asm-defns.h>
 #include <asm/alternative-asm.h>
+#include <asm/spec_ctrl_asm.h>
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index e9b8ed4c96..b82e18dd62 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -2069,7 +2069,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
              */
             if ( *last_id != next_id )
             {
-                wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+                spec_ctrl_new_guest_context();
                 *last_id = next_id;
             }
         }
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 459c64d139..5636853aae 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -775,6 +775,14 @@ static void __init ibpb_calculations(void)
         return;
     }
 
+    /*
+     * AMD/Hygon CPUs to date (June 2022) don't flush the the RAS.  Future
+     * CPUs are expected to enumerate IBPB_RET when this has been fixed.
+     * Until then, cover the difference with the software sequence.
+     */
+    if ( boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_IBPB_RET) )
+        setup_force_cpu_cap(X86_BUG_IBPB_NO_RET);
+
     /*
      * IBPB-on-entry mitigations for Branch Type Confusion.
      *
diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h
index b233e5835f..bdb119a34c 100644
--- a/xen/include/asm-x86/cpufeatures.h
+++ b/xen/include/asm-x86/cpufeatures.h
@@ -48,6 +48,7 @@ XEN_CPUFEATURE(IBPB_ENTRY_HVM,    X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for
 
 #define X86_BUG_FPU_PTRS          X86_BUG( 0) /* (F)X{SAVE,RSTOR} doesn't save/restore FOP/FIP/FDP. */
 #define X86_BUG_CLFLUSH_MFENCE    X86_BUG( 2) /* MFENCE needed to serialise CLFLUSH */
+#define X86_BUG_IBPB_NO_RET       X86_BUG( 3) /* IBPB doesn't flush the RSB/RAS */
 
 /* Total number of capability words, inc synth and bug words. */
 #define NCAPINTS (FSCAPINTS + X86_NR_SYNTH + X86_NR_BUG) /* N 32-bit words worth of info */
diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h
index 33e845991b..e400ff2273 100644
--- a/xen/include/asm-x86/spec_ctrl.h
+++ b/xen/include/asm-x86/spec_ctrl.h
@@ -65,6 +65,28 @@
 void init_speculation_mitigations(void);
 void spec_ctrl_init_domain(struct domain *d);
 
+/*
+ * Switch to a new guest prediction context.
+ *
+ * This flushes all indirect branch predictors (BTB, RSB/RAS), so guest code
+ * which has previously run on this CPU can't attack subsequent guest code.
+ *
+ * As this flushes the RSB/RAS, it destroys the predictions of the calling
+ * context.  For best performace, arrange for this to be used when we're going
+ * to jump out of the current context, e.g. with reset_stack_and_jump().
+ *
+ * For hardware which mis-implements IBPB, fix up by flushing the RSB/RAS
+ * manually.
+ */
+static always_inline void spec_ctrl_new_guest_context(void)
+{
+    wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB);
+
+    /* (ab)use alternative_input() to specify clobbers. */
+    alternative_input("", "DO_OVERWRITE_RSB", X86_BUG_IBPB_NO_RET,
+                      : "rax", "rcx");
+}
+
 extern int8_t opt_ibpb_ctxt_switch;
 extern bool opt_ssbd;
 extern int8_t opt_eager_fpu;
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Thu Nov 10 11:11:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 10 Nov 2022 11:11:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441772.695831 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot5St-0002lq-O1; Thu, 10 Nov 2022 11:11:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441772.695831; Thu, 10 Nov 2022 11:11:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot5St-0002li-LL; Thu, 10 Nov 2022 11:11:23 +0000
Received: by outflank-mailman (input) for mailman id 441772;
 Thu, 10 Nov 2022 11:11:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5Ss-0002lX-Bs
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5Ss-00038L-B8
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5Ss-0001Zs-8a
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=cLUrDPXvaF/rrss6sK+CnDJqs75+FthLxP9zvrOMKyE=; b=ZmgDf9ZJrdyvVV51oRx26P93PC
	XSMHGAiV65EU9WHNmQaI9FHS2lZ9Em7vG/GsiGSRX/00Ao5E6hxTFTPtkOdCifyNbsj876SzPsk7l
	mZ3IzCfePZJHSjsrEl/1buo5pmM12uL+nwaSvZNx4lExJbcxXgOHmy/TBUfViqvUPXYc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] tools/xenstore: call remove_domid_from_perm() for special nodes
Message-Id: <E1ot5Ss-0001Zs-8a@xenbits.xenproject.org>
Date: Thu, 10 Nov 2022 11:11:22 +0000

commit 201552c5ca503b02487f14233b4f4c303cc537e8
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 9 11:01:56 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 9 11:01:56 2022 +0100

    tools/xenstore: call remove_domid_from_perm() for special nodes
    
    When destroying a domain, any stale permissions of the domain must be
    removed from the special nodes "@...", too. This was not done in the
    fix for XSA-322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    master commit: 0751a75e3996cf6efd3925a90b4776660d8df2bc
    master date: 2022-11-02 12:08:22 +0100
---
 tools/xenstore/xenstored_domain.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index ee4b19387d..8cc36ee44c 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -196,6 +196,27 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static void remove_domid_from_perm(struct node_perms *perms,
+				   struct domain *domain)
+{
+	unsigned int cur, new;
+
+	if (perms->p[0].id == domain->domid)
+		perms->p[0].id = priv_domid;
+
+	for (cur = new = 1; cur < perms->num; cur++) {
+		if (perms->p[cur].id == domain->domid)
+			continue;
+
+		if (new != cur)
+			perms->p[new] = perms->p[cur];
+
+		new++;
+	}
+
+	perms->num = new;
+}
+
 static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
 				  struct node *node, void *arg)
 {
@@ -246,6 +267,9 @@ static void domain_tree_remove(struct domain *domain)
 			syslog(LOG_ERR,
 			       "error when looking for orphaned nodes\n");
 	}
+
+	remove_domid_from_perm(&dom_release_perms, domain);
+	remove_domid_from_perm(&dom_introduce_perms, domain);
 }
 
 static int destroy_domain(void *_domain)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Thu Nov 10 11:11:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 10 Nov 2022 11:11:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441773.695835 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot5T3-0002oY-Pk; Thu, 10 Nov 2022 11:11:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441773.695835; Thu, 10 Nov 2022 11:11:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot5T3-0002oQ-My; Thu, 10 Nov 2022 11:11:33 +0000
Received: by outflank-mailman (input) for mailman id 441773;
 Thu, 10 Nov 2022 11:11:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5T2-0002oI-Fq
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5T2-00038Z-F4
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot5T2-0001aJ-Do
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 11:11:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=cTQTfMZXflx/KQ+xzxY5krTzyWxAAohcrLM2XeqWD6g=; b=i8duCklWC1RNenvN6R33qNjoDo
	FpxpssK7fZiNGWkzt9ZObMXQ64m+a7RVnLwAti9I2f/ZQDvF7K2srgkbmLUU+2sLsIvvPdzLGfFYY
	hXGuwepxc6fYOPgT2tBUYw+8CniaflSBtmWm3epopJvvpqjzhNvWJ0buJg5F7575KLL0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] xen/sched: migrate timers to correct cpus after suspend
Message-Id: <E1ot5T2-0001aJ-Do@xenbits.xenproject.org>
Date: Thu, 10 Nov 2022 11:11:32 +0000

commit 625efe28ab5309ab83f7826ed1de4966ede2f191
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 9 11:02:19 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 9 11:02:19 2022 +0100

    xen/sched: migrate timers to correct cpus after suspend
    
    Today all timers are migrated to cpu 0 when the system is being
    suspended. They are not migrated back after resuming the system again.
    
    This results (at least) to visible problems with the credit scheduler,
    as the timer isn't handled on the cpu it was expected to occur, which
    will result in an ASSERT() triggering. Other more subtle problems, like
    uninterrupted elongated time slices, are probable. The least effect
    will be worse performance on cpu 0 resulting from most scheduling
    related timer interrupts happening there after suspend/resume.
    
    Add migrating the scheduling related timers of a specific cpu from cpu
    0 back to its original cpu when that cpu has gone up when resuming the
    system.
    
    Fixes: 0763cd268789 ("xen/sched: don't disable scheduler on cpus during suspend")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
    Acked-by: Dario Faggioli <dfaggioli@suse.com>
    master commit: 37f82facd62f720fdcec104f72f86b8c6c214820
    master date: 2022-11-04 09:03:23 +0100
---
 xen/common/sched/core.c    | 29 +++++++++++++++++++++++
 xen/common/sched/cpupool.c |  2 ++
 xen/common/sched/credit.c  | 13 +++++++++++
 xen/common/sched/private.h | 10 ++++++++
 xen/common/sched/rt.c      | 58 ++++++++++++++++++++++++++++++++--------------
 5 files changed, 94 insertions(+), 18 deletions(-)

diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index 9173cf690c..03ace41540 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -1284,6 +1284,35 @@ static int cpu_disable_scheduler_check(unsigned int cpu)
     return 0;
 }
 
+/*
+ * Called after a cpu has come up again in a suspend/resume cycle.
+ * Migrate all timers for this cpu (they have been migrated to cpu 0 when the
+ * cpu was going down).
+ * Note that only timers related to a physical cpu are migrated, not the ones
+ * related to a vcpu or domain.
+ */
+void sched_migrate_timers(unsigned int cpu)
+{
+    struct sched_resource *sr;
+
+    rcu_read_lock(&sched_res_rculock);
+
+    sr = get_sched_res(cpu);
+
+    /*
+     * Note that on a system with parked cpus (e.g. smt=0 on Intel cpus) this
+     * will be called for the parked cpus, too, so the case for no scheduling
+     * resource being available must be considered.
+     */
+    if ( sr && sr->master_cpu == cpu )
+    {
+        migrate_timer(&sr->s_timer, cpu);
+        sched_move_timers(sr->scheduler, sr);
+    }
+
+    rcu_read_unlock(&sched_res_rculock);
+}
+
 /*
  * In general, this must be called with the scheduler lock held, because the
  * adjust_affinity hook may want to modify the vCPU state. However, when the
diff --git a/xen/common/sched/cpupool.c b/xen/common/sched/cpupool.c
index b5a948639a..a083c5a3c6 100644
--- a/xen/common/sched/cpupool.c
+++ b/xen/common/sched/cpupool.c
@@ -1022,6 +1022,8 @@ static int cpu_callback(
     case CPU_ONLINE:
         if ( system_state <= SYS_STATE_active )
             rc = cpupool_cpu_add(cpu);
+        else
+            sched_migrate_timers(cpu);
         break;
     case CPU_DOWN_PREPARE:
         /* Suspend/Resume don't change assignments of cpus to cpupools. */
diff --git a/xen/common/sched/credit.c b/xen/common/sched/credit.c
index d0aa017c64..a432a7e000 100644
--- a/xen/common/sched/credit.c
+++ b/xen/common/sched/credit.c
@@ -614,6 +614,18 @@ init_pdata(struct csched_private *prv, struct csched_pcpu *spc, int cpu)
     spc->nr_runnable = 0;
 }
 
+static void
+csched_move_timers(const struct scheduler *ops, struct sched_resource *sr)
+{
+    struct csched_private *prv = CSCHED_PRIV(ops);
+    struct csched_pcpu *spc = sr->sched_priv;
+
+    if ( sr->master_cpu == prv->master )
+        migrate_timer(&prv->master_ticker, prv->master);
+
+    migrate_timer(&spc->ticker, sr->master_cpu);
+}
+
 /* Change the scheduler of cpu to us (Credit). */
 static spinlock_t *
 csched_switch_sched(struct scheduler *new_ops, unsigned int cpu,
@@ -2267,6 +2279,7 @@ static const struct scheduler sched_credit_def = {
     .switch_sched   = csched_switch_sched,
     .alloc_domdata  = csched_alloc_domdata,
     .free_domdata   = csched_free_domdata,
+    .move_timers    = csched_move_timers,
 };
 
 REGISTER_SCHEDULER(sched_credit_def);
diff --git a/xen/common/sched/private.h b/xen/common/sched/private.h
index 3bab78ccb2..8c07f033d3 100644
--- a/xen/common/sched/private.h
+++ b/xen/common/sched/private.h
@@ -331,6 +331,8 @@ struct scheduler {
                                     struct xen_sysctl_scheduler_op *);
     void         (*dump_settings)  (const struct scheduler *);
     void         (*dump_cpu_state) (const struct scheduler *, int);
+    void         (*move_timers)    (const struct scheduler *,
+                                    struct sched_resource *);
 };
 
 static inline int sched_init(struct scheduler *s)
@@ -485,6 +487,13 @@ static inline int sched_adjust_cpupool(const struct scheduler *s,
     return s->adjust_global ? s->adjust_global(s, op) : 0;
 }
 
+static inline void sched_move_timers(const struct scheduler *s,
+                                     struct sched_resource *sr)
+{
+    if ( s->move_timers )
+        s->move_timers(s, sr);
+}
+
 static inline void sched_unit_pause_nosync(const struct sched_unit *unit)
 {
     struct vcpu *v;
@@ -622,6 +631,7 @@ struct cpu_rm_data *alloc_cpu_rm_data(unsigned int cpu, bool aff_alloc);
 void free_cpu_rm_data(struct cpu_rm_data *mem, unsigned int cpu);
 int schedule_cpu_rm(unsigned int cpu, struct cpu_rm_data *mem);
 int sched_move_domain(struct domain *d, struct cpupool *c);
+void sched_migrate_timers(unsigned int cpu);
 struct cpupool *cpupool_get_by_id(unsigned int poolid);
 void cpupool_put(struct cpupool *pool);
 int cpupool_add_domain(struct domain *d, unsigned int poolid);
diff --git a/xen/common/sched/rt.c b/xen/common/sched/rt.c
index ec2ca1bebc..fd62ddc0d5 100644
--- a/xen/common/sched/rt.c
+++ b/xen/common/sched/rt.c
@@ -750,6 +750,27 @@ rt_switch_sched(struct scheduler *new_ops, unsigned int cpu,
     return &prv->lock;
 }
 
+static void move_repl_timer(struct rt_private *prv, unsigned int old_cpu)
+{
+    cpumask_t *online = get_sched_res(old_cpu)->cpupool->res_valid;
+    unsigned int new_cpu = cpumask_cycle(old_cpu, online);
+
+    /*
+     * Make sure the timer run on one of the cpus that are still available
+     * to this scheduler. If there aren't any left, it means it's the time
+     * to just kill it.
+     */
+    if ( new_cpu >= nr_cpu_ids )
+    {
+        kill_timer(&prv->repl_timer);
+        dprintk(XENLOG_DEBUG, "RTDS: timer killed on cpu %d\n", old_cpu);
+    }
+    else
+    {
+        migrate_timer(&prv->repl_timer, new_cpu);
+    }
+}
+
 static void
 rt_deinit_pdata(const struct scheduler *ops, void *pcpu, int cpu)
 {
@@ -759,25 +780,25 @@ rt_deinit_pdata(const struct scheduler *ops, void *pcpu, int cpu)
     spin_lock_irqsave(&prv->lock, flags);
 
     if ( prv->repl_timer.cpu == cpu )
-    {
-        cpumask_t *online = get_sched_res(cpu)->cpupool->res_valid;
-        unsigned int new_cpu = cpumask_cycle(cpu, online);
+        move_repl_timer(prv, cpu);
 
-        /*
-         * Make sure the timer run on one of the cpus that are still available
-         * to this scheduler. If there aren't any left, it means it's the time
-         * to just kill it.
-         */
-        if ( new_cpu >= nr_cpu_ids )
-        {
-            kill_timer(&prv->repl_timer);
-            dprintk(XENLOG_DEBUG, "RTDS: timer killed on cpu %d\n", cpu);
-        }
-        else
-        {
-            migrate_timer(&prv->repl_timer, new_cpu);
-        }
-    }
+    spin_unlock_irqrestore(&prv->lock, flags);
+}
+
+static void
+rt_move_timers(const struct scheduler *ops, struct sched_resource *sr)
+{
+    unsigned long flags;
+    struct rt_private *prv = rt_priv(ops);
+    unsigned int old_cpu;
+
+    spin_lock_irqsave(&prv->lock, flags);
+
+    old_cpu = prv->repl_timer.cpu;
+    if ( prv->repl_timer.status != TIMER_STATUS_invalid &&
+         prv->repl_timer.status != TIMER_STATUS_killed &&
+         !cpumask_test_cpu(old_cpu, sr->cpupool->res_valid) )
+        move_repl_timer(prv, old_cpu);
 
     spin_unlock_irqrestore(&prv->lock, flags);
 }
@@ -1555,6 +1576,7 @@ static const struct scheduler sched_rtds_def = {
     .sleep          = rt_unit_sleep,
     .wake           = rt_unit_wake,
     .context_saved  = rt_context_saved,
+    .move_timers    = rt_move_timers,
 };
 
 REGISTER_SCHEDULER(sched_rtds_def);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Thu Nov 10 13:11:10 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 10 Nov 2022 13:11:10 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441803.695855 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot7Kg-0008Ta-Rf; Thu, 10 Nov 2022 13:11:02 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441803.695855; Thu, 10 Nov 2022 13:11:02 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot7Kg-0008TS-OU; Thu, 10 Nov 2022 13:11:02 +0000
Received: by outflank-mailman (input) for mailman id 441803;
 Thu, 10 Nov 2022 13:11:01 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot7Kf-0008TM-Ou
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 13:11:01 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot7Kf-00061q-ME
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 13:11:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot7Kf-0006NP-LF
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 13:11:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=YLlppKyRzS/WtaggqYsUCdLdeDP5E2g0XodBoa+VcoI=; b=o0vXP5Z+Ir7BTjiwOqSptCC7YK
	h2avIBLX8StrHro8eSqMHGhBOeSUUiqMjgsOp8E8U1hRRkNXw3THsxi8Yb9VAwoaaejJC8Tk8Iwxf
	Gf2Ei7KPwbQ2fLPfTKHcYqCFsGBk4zfFh6z5enQLSI7J+tHBpgMFg9S+Hw1Wb/FEQDNE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] tools/xenstore: call remove_domid_from_perm() for special nodes
Message-Id: <E1ot7Kf-0006NP-LF@xenbits.xenproject.org>
Date: Thu, 10 Nov 2022 13:11:01 +0000

commit a524495aac037d48e3163ad29099030403298f6f
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 9 10:59:42 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 9 10:59:42 2022 +0100

    tools/xenstore: call remove_domid_from_perm() for special nodes
    
    When destroying a domain, any stale permissions of the domain must be
    removed from the special nodes "@...", too. This was not done in the
    fix for XSA-322.
    
    Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    master commit: 0751a75e3996cf6efd3925a90b4776660d8df2bc
    master date: 2022-11-02 12:08:22 +0100
---
 tools/xenstore/xenstored_domain.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 8b134017a2..ddd49eddfa 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -227,6 +227,27 @@ static void unmap_interface(void *interface)
 	xengnttab_unmap(*xgt_handle, interface, 1);
 }
 
+static void remove_domid_from_perm(struct node_perms *perms,
+				   struct domain *domain)
+{
+	unsigned int cur, new;
+
+	if (perms->p[0].id == domain->domid)
+		perms->p[0].id = priv_domid;
+
+	for (cur = new = 1; cur < perms->num; cur++) {
+		if (perms->p[cur].id == domain->domid)
+			continue;
+
+		if (new != cur)
+			perms->p[new] = perms->p[cur];
+
+		new++;
+	}
+
+	perms->num = new;
+}
+
 static int domain_tree_remove_sub(const void *ctx, struct connection *conn,
 				  struct node *node, void *arg)
 {
@@ -277,6 +298,9 @@ static void domain_tree_remove(struct domain *domain)
 			syslog(LOG_ERR,
 			       "error when looking for orphaned nodes\n");
 	}
+
+	remove_domid_from_perm(&dom_release_perms, domain);
+	remove_domid_from_perm(&dom_introduce_perms, domain);
 }
 
 static int destroy_domain(void *_domain)
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Thu Nov 10 13:11:12 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 10 Nov 2022 13:11:12 +0000
Received: from list by lists.xenproject.org with outflank-mailman.441804.695858 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot7Kq-0008VX-T6; Thu, 10 Nov 2022 13:11:12 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 441804.695858; Thu, 10 Nov 2022 13:11:12 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ot7Kq-0008VP-QG; Thu, 10 Nov 2022 13:11:12 +0000
Received: by outflank-mailman (input) for mailman id 441804;
 Thu, 10 Nov 2022 13:11:11 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot7Kp-0008VC-Qo
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 13:11:11 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot7Kp-000629-Pm
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 13:11:11 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ot7Kp-0006Nr-Ol
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 13:11:11 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=tGHQ5yYqDt+datcSIKHFbGlhF0W5KNGphZTOOhb8JXU=; b=t2G7x7bNUcxn52N3Lodn5hf4GO
	yD11+0ea+DU/fRKJt57/5QwzikIR4aGJAlvq3LkXuXOZ9p3I7FwajLheMPsgoE4YMxncxniPmLdeU
	sVtGJHEe2NsQXXMZwCqdltjBOui0FB3s+pDFYdplu9wOlXMHa3S7kmsWofo2Vig/3ZFs=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] xen/sched: migrate timers to correct cpus after suspend
Message-Id: <E1ot7Kp-0006Nr-Ol@xenbits.xenproject.org>
Date: Thu, 10 Nov 2022 13:11:11 +0000

commit 1dc6dccb1a8752f200ec2612b2bd091bbf88b231
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 9 11:00:04 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 9 11:00:04 2022 +0100

    xen/sched: migrate timers to correct cpus after suspend
    
    Today all timers are migrated to cpu 0 when the system is being
    suspended. They are not migrated back after resuming the system again.
    
    This results (at least) to visible problems with the credit scheduler,
    as the timer isn't handled on the cpu it was expected to occur, which
    will result in an ASSERT() triggering. Other more subtle problems, like
    uninterrupted elongated time slices, are probable. The least effect
    will be worse performance on cpu 0 resulting from most scheduling
    related timer interrupts happening there after suspend/resume.
    
    Add migrating the scheduling related timers of a specific cpu from cpu
    0 back to its original cpu when that cpu has gone up when resuming the
    system.
    
    Fixes: 0763cd268789 ("xen/sched: don't disable scheduler on cpus during suspend")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
    Acked-by: Dario Faggioli <dfaggioli@suse.com>
    master commit: 37f82facd62f720fdcec104f72f86b8c6c214820
    master date: 2022-11-04 09:03:23 +0100
---
 xen/common/sched/core.c    | 29 +++++++++++++++++++++++
 xen/common/sched/cpupool.c |  2 ++
 xen/common/sched/credit.c  | 13 +++++++++++
 xen/common/sched/private.h | 10 ++++++++
 xen/common/sched/rt.c      | 58 ++++++++++++++++++++++++++++++++--------------
 5 files changed, 94 insertions(+), 18 deletions(-)

diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index 9173cf690c..03ace41540 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -1284,6 +1284,35 @@ static int cpu_disable_scheduler_check(unsigned int cpu)
     return 0;
 }
 
+/*
+ * Called after a cpu has come up again in a suspend/resume cycle.
+ * Migrate all timers for this cpu (they have been migrated to cpu 0 when the
+ * cpu was going down).
+ * Note that only timers related to a physical cpu are migrated, not the ones
+ * related to a vcpu or domain.
+ */
+void sched_migrate_timers(unsigned int cpu)
+{
+    struct sched_resource *sr;
+
+    rcu_read_lock(&sched_res_rculock);
+
+    sr = get_sched_res(cpu);
+
+    /*
+     * Note that on a system with parked cpus (e.g. smt=0 on Intel cpus) this
+     * will be called for the parked cpus, too, so the case for no scheduling
+     * resource being available must be considered.
+     */
+    if ( sr && sr->master_cpu == cpu )
+    {
+        migrate_timer(&sr->s_timer, cpu);
+        sched_move_timers(sr->scheduler, sr);
+    }
+
+    rcu_read_unlock(&sched_res_rculock);
+}
+
 /*
  * In general, this must be called with the scheduler lock held, because the
  * adjust_affinity hook may want to modify the vCPU state. However, when the
diff --git a/xen/common/sched/cpupool.c b/xen/common/sched/cpupool.c
index b5a948639a..a083c5a3c6 100644
--- a/xen/common/sched/cpupool.c
+++ b/xen/common/sched/cpupool.c
@@ -1022,6 +1022,8 @@ static int cpu_callback(
     case CPU_ONLINE:
         if ( system_state <= SYS_STATE_active )
             rc = cpupool_cpu_add(cpu);
+        else
+            sched_migrate_timers(cpu);
         break;
     case CPU_DOWN_PREPARE:
         /* Suspend/Resume don't change assignments of cpus to cpupools. */
diff --git a/xen/common/sched/credit.c b/xen/common/sched/credit.c
index d0aa017c64..a432a7e000 100644
--- a/xen/common/sched/credit.c
+++ b/xen/common/sched/credit.c
@@ -614,6 +614,18 @@ init_pdata(struct csched_private *prv, struct csched_pcpu *spc, int cpu)
     spc->nr_runnable = 0;
 }
 
+static void
+csched_move_timers(const struct scheduler *ops, struct sched_resource *sr)
+{
+    struct csched_private *prv = CSCHED_PRIV(ops);
+    struct csched_pcpu *spc = sr->sched_priv;
+
+    if ( sr->master_cpu == prv->master )
+        migrate_timer(&prv->master_ticker, prv->master);
+
+    migrate_timer(&spc->ticker, sr->master_cpu);
+}
+
 /* Change the scheduler of cpu to us (Credit). */
 static spinlock_t *
 csched_switch_sched(struct scheduler *new_ops, unsigned int cpu,
@@ -2267,6 +2279,7 @@ static const struct scheduler sched_credit_def = {
     .switch_sched   = csched_switch_sched,
     .alloc_domdata  = csched_alloc_domdata,
     .free_domdata   = csched_free_domdata,
+    .move_timers    = csched_move_timers,
 };
 
 REGISTER_SCHEDULER(sched_credit_def);
diff --git a/xen/common/sched/private.h b/xen/common/sched/private.h
index 0126a4bb9e..0527a8c70d 100644
--- a/xen/common/sched/private.h
+++ b/xen/common/sched/private.h
@@ -331,6 +331,8 @@ struct scheduler {
                                     struct xen_sysctl_scheduler_op *);
     void         (*dump_settings)  (const struct scheduler *);
     void         (*dump_cpu_state) (const struct scheduler *, int);
+    void         (*move_timers)    (const struct scheduler *,
+                                    struct sched_resource *);
 };
 
 static inline int sched_init(struct scheduler *s)
@@ -485,6 +487,13 @@ static inline int sched_adjust_cpupool(const struct scheduler *s,
     return s->adjust_global ? s->adjust_global(s, op) : 0;
 }
 
+static inline void sched_move_timers(const struct scheduler *s,
+                                     struct sched_resource *sr)
+{
+    if ( s->move_timers )
+        s->move_timers(s, sr);
+}
+
 static inline void sched_unit_pause_nosync(const struct sched_unit *unit)
 {
     struct vcpu *v;
@@ -622,6 +631,7 @@ struct cpu_rm_data *alloc_cpu_rm_data(unsigned int cpu, bool aff_alloc);
 void free_cpu_rm_data(struct cpu_rm_data *mem, unsigned int cpu);
 int schedule_cpu_rm(unsigned int cpu, struct cpu_rm_data *mem);
 int sched_move_domain(struct domain *d, struct cpupool *c);
+void sched_migrate_timers(unsigned int cpu);
 struct cpupool *cpupool_get_by_id(unsigned int poolid);
 void cpupool_put(struct cpupool *pool);
 int cpupool_add_domain(struct domain *d, unsigned int poolid);
diff --git a/xen/common/sched/rt.c b/xen/common/sched/rt.c
index ec2ca1bebc..fd62ddc0d5 100644
--- a/xen/common/sched/rt.c
+++ b/xen/common/sched/rt.c
@@ -750,6 +750,27 @@ rt_switch_sched(struct scheduler *new_ops, unsigned int cpu,
     return &prv->lock;
 }
 
+static void move_repl_timer(struct rt_private *prv, unsigned int old_cpu)
+{
+    cpumask_t *online = get_sched_res(old_cpu)->cpupool->res_valid;
+    unsigned int new_cpu = cpumask_cycle(old_cpu, online);
+
+    /*
+     * Make sure the timer run on one of the cpus that are still available
+     * to this scheduler. If there aren't any left, it means it's the time
+     * to just kill it.
+     */
+    if ( new_cpu >= nr_cpu_ids )
+    {
+        kill_timer(&prv->repl_timer);
+        dprintk(XENLOG_DEBUG, "RTDS: timer killed on cpu %d\n", old_cpu);
+    }
+    else
+    {
+        migrate_timer(&prv->repl_timer, new_cpu);
+    }
+}
+
 static void
 rt_deinit_pdata(const struct scheduler *ops, void *pcpu, int cpu)
 {
@@ -759,25 +780,25 @@ rt_deinit_pdata(const struct scheduler *ops, void *pcpu, int cpu)
     spin_lock_irqsave(&prv->lock, flags);
 
     if ( prv->repl_timer.cpu == cpu )
-    {
-        cpumask_t *online = get_sched_res(cpu)->cpupool->res_valid;
-        unsigned int new_cpu = cpumask_cycle(cpu, online);
+        move_repl_timer(prv, cpu);
 
-        /*
-         * Make sure the timer run on one of the cpus that are still available
-         * to this scheduler. If there aren't any left, it means it's the time
-         * to just kill it.
-         */
-        if ( new_cpu >= nr_cpu_ids )
-        {
-            kill_timer(&prv->repl_timer);
-            dprintk(XENLOG_DEBUG, "RTDS: timer killed on cpu %d\n", cpu);
-        }
-        else
-        {
-            migrate_timer(&prv->repl_timer, new_cpu);
-        }
-    }
+    spin_unlock_irqrestore(&prv->lock, flags);
+}
+
+static void
+rt_move_timers(const struct scheduler *ops, struct sched_resource *sr)
+{
+    unsigned long flags;
+    struct rt_private *prv = rt_priv(ops);
+    unsigned int old_cpu;
+
+    spin_lock_irqsave(&prv->lock, flags);
+
+    old_cpu = prv->repl_timer.cpu;
+    if ( prv->repl_timer.status != TIMER_STATUS_invalid &&
+         prv->repl_timer.status != TIMER_STATUS_killed &&
+         !cpumask_test_cpu(old_cpu, sr->cpupool->res_valid) )
+        move_repl_timer(prv, old_cpu);
 
     spin_unlock_irqrestore(&prv->lock, flags);
 }
@@ -1555,6 +1576,7 @@ static const struct scheduler sched_rtds_def = {
     .sleep          = rt_unit_sleep,
     .wake           = rt_unit_wake,
     .context_saved  = rt_context_saved,
+    .move_timers    = rt_move_timers,
 };
 
 REGISTER_SCHEDULER(sched_rtds_def);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Thu Nov 10 19:22:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 10 Nov 2022 19:22:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.442159.696194 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otD7j-0000QG-IW; Thu, 10 Nov 2022 19:22:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 442159.696194; Thu, 10 Nov 2022 19:22:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otD7j-0000Q9-Fq; Thu, 10 Nov 2022 19:22:03 +0000
Received: by outflank-mailman (input) for mailman id 442159;
 Thu, 10 Nov 2022 19:22:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otD7i-0000Q3-4Z
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 19:22:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otD7i-0007LG-3i
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 19:22:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otD7i-0002Rv-1w
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 19:22:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=8ojQeLB9qiG4JxWufoq2qzY+7vDGvfF/1djDDKFd8ys=; b=V/sswziutITGRvpaJO5OQ2bl3x
	Jhw+N5hrignkldLevACF4aqH5k+uWB+SJXSQLe8cstwqkra0mcdZUOBblEQIc2DwzsQlD4pIdeHjm
	igU1hRgSZqVzUNBkqzrlnRZaVXIXK6QdS1BB/HJxYwtMLrumGG1oywP+2cJSzdED5Tww=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/ocaml/xenstored/store.ml: fix build error
Message-Id: <E1otD7i-0002Rv-1w@xenbits.xenproject.org>
Date: Thu, 10 Nov 2022 19:22:02 +0000

commit 124492eff8e4acdaaed939fa9406b108c55fec73
Author:     Edwin Török <edvin.torok@citrix.com>
AuthorDate: Wed Nov 9 10:48:33 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 9 10:48:33 2022 +0100

    tools/ocaml/xenstored/store.ml: fix build error
    
    Building with Dune in release mode fails with:
    ```
    File "ocaml/xenstored/store.ml", line 464, characters 13-32:
    Warning 18: this type-based record disambiguation is not principal.
    File "ocaml/xenstored/store.ml", line 1:
    Error: Some fatal warnings were triggered (1 occurrences)
    ```
    
    This is a warning to help keep the code futureproof, quoting from its
    documentation:
    > Check information path during type-checking, to make sure that all types are
    > derived in a principal way. When using labelled arguments and/or polymorphic
    > methods, this flag is required to ensure future versions of the compiler will
    > be able to infer types correctly, even if internal algorithms change. All
    > programs accepted in -principal mode are also accepted in the default mode with
    > equivalent types, but different binary signatures, and this may slow down type
    > checking; yet it is a good idea to use it once before publishing source code.
    
    Fixes: db471408edd46 "tools/ocaml/xenstored: Fix quota bypass on domain shutdown"
    
    Signed-off-by: Edwin Török <edvin.torok@citrix.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/ocaml/xenstored/store.ml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
index 70f0c83de4..c94dbf3a62 100644
--- a/tools/ocaml/xenstored/store.ml
+++ b/tools/ocaml/xenstored/store.ml
@@ -461,7 +461,7 @@ let reset_permissions store domid =
 		| Some perms ->
 			if perms <> node.perms then
 				Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
-			Some { node with perms }
+			Some { node with Node.perms }
 	) store.root
 
 type ops = {
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 10 19:22:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 10 Nov 2022 19:22:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.442160.696199 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otD7t-0000SE-Ka; Thu, 10 Nov 2022 19:22:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 442160.696199; Thu, 10 Nov 2022 19:22:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otD7t-0000S6-Hh; Thu, 10 Nov 2022 19:22:13 +0000
Received: by outflank-mailman (input) for mailman id 442160;
 Thu, 10 Nov 2022 19:22:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otD7s-0000Rv-9I
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 19:22:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otD7s-0007LM-8e
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 19:22:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otD7s-0002Tt-5z
 for xen-changelog@lists.xenproject.org; Thu, 10 Nov 2022 19:22:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=0TniUkfNJ1TNET3M4b8wKVFJZNxHRFitut4wmY7IpZ8=; b=eOpBxxypF4EFsqTzj7Ogs79zTg
	rV21oO+5wc4e0uANO9IJ8eVSwBiM3g0z0h35ytRCzRXCgkoid5MHj/Ji5jQ4Vjk6U1U/VUFylC/VA
	9MQ0xDJ2Rlkh+U6Yt2I0TFIU0K1X2V0fBIZMHDUxM6uD99HDcbuNma6zv94QXHMen6Rc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/hotplug: fix systemd unit dependencies
Message-Id: <E1otD7s-0002Tt-5z@xenbits.xenproject.org>
Date: Thu, 10 Nov 2022 19:22:12 +0000

commit aa1bf3858551b7cd1facfb116fe35830aceac497
Author:     Juergen Gross <jgross@suse.com>
AuthorDate: Wed Nov 9 10:48:59 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Wed Nov 9 10:48:59 2022 +0100

    tools/hotplug: fix systemd unit dependencies
    
    Commit 1283af6465cd ("tools/xenstore: remove XEN_LIB_STORED and
    XENSTORED_ROOTDIR") removed the systemd file var-lib-xenstored.mount
    without removing dependencies to this file.
    
    Fixes: 1283af6465cd ("tools/xenstore: remove XEN_LIB_STORED and XENSTORED_ROOTDIR")
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/hotplug/Linux/systemd/xenstored.service.in | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/tools/hotplug/Linux/systemd/xenstored.service.in b/tools/hotplug/Linux/systemd/xenstored.service.in
index 80c1d408a5..261077dc92 100644
--- a/tools/hotplug/Linux/systemd/xenstored.service.in
+++ b/tools/hotplug/Linux/systemd/xenstored.service.in
@@ -1,7 +1,7 @@
 [Unit]
 Description=The Xen xenstore
-Requires=proc-xen.mount var-lib-xenstored.mount
-After=proc-xen.mount var-lib-xenstored.mount
+Requires=proc-xen.mount
+After=proc-xen.mount
 Before=libvirtd.service libvirt-guests.service
 RefuseManualStop=true
 ConditionPathExists=/proc/xen/capabilities
@@ -16,4 +16,3 @@ ExecStart=@XEN_SCRIPT_DIR@/launch-xenstore
 [Install]
 WantedBy=multi-user.target
 Also=proc-xen.mount
-Also=var-lib-xenstored.mount
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Fri Nov 11 05:55:12 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Fri, 11 Nov 2022 05:55:12 +0000
Received: from list by lists.xenproject.org with outflank-mailman.442315.696401 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otN0J-0003x7-BJ; Fri, 11 Nov 2022 05:55:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 442315.696401; Fri, 11 Nov 2022 05:55:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otN0J-0003wz-8O; Fri, 11 Nov 2022 05:55:03 +0000
Received: by outflank-mailman (input) for mailman id 442315;
 Fri, 11 Nov 2022 05:55:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otN0I-0003wt-9a
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 05:55:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otN0I-0005GX-8I
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 05:55:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otN0I-0000mV-7N
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 05:55:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ei1WNvPzuqGklo1yyYk0dJXbU97XwrBL+4YcXnrPI4k=; b=NqIpOELG3XCv6xmvKp9KKAgtXX
	/83IQP1IC0fncITtti1xR6u8f31kZ2h1zHBQiPGKQuyHzf3EYAELzdpNXzbwy/Rq7o1xmBs8+9O9f
	N02Q6B5G1i5Bb90q8++/gbTB49iwrD0JDXooi+SjOj+FZgN9NliuNDF1OhDP/INBD7f4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] Revert "x86/HVM: also dump stacks from show_execution_state()"
Message-Id: <E1otN0I-0000mV-7N@xenbits.xenproject.org>
Date: Fri, 11 Nov 2022 05:55:02 +0000

commit 8febf78f1ed075292b664bf8c60c5f472028f955
Author:     Roger Pau Monne <roger.pau@citrix.com>
AuthorDate: Fri Nov 4 15:43:37 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 9 20:07:45 2022 +0000

    Revert "x86/HVM: also dump stacks from show_execution_state()"
    
    This reverts commit adb715db698bc8ec3b88c24eb88b21e9da5b6c07.
    
    The dumping of stacks for HVM guests is problematic, since it requires
    taking the p2m lock in order to walk the guest page tables and the p2m.
    
    The suggested solution to the issue is to introduce and use a lockless p2m
    walker, that relies on being executed with interrupts disabled in order to
    prevent any p2m pages from being freed while doing the walk.
    
    Note that modifications of p2m entries are already done atomically in order
    to prevent the hardware walker from seeing partially updated values.
    
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/arch/x86/traps.c | 33 +++++++++------------------------
 1 file changed, 9 insertions(+), 24 deletions(-)

diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 7207390118..56e59896bf 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -278,6 +278,10 @@ static void show_guest_stack(struct vcpu *v, const struct cpu_user_regs *regs)
     unsigned long mask = STACK_SIZE;
     void *stack_page = NULL;
 
+    /* Avoid HVM as we don't know what the stack looks like. */
+    if ( is_hvm_vcpu(v) )
+        return;
+
     if ( is_pv_32bit_vcpu(v) )
     {
         compat_show_guest_stack(v, regs, debug_stack_lines);
@@ -591,6 +595,9 @@ static void show_stack(const struct cpu_user_regs *regs)
     unsigned long *stack = ESP_BEFORE_EXCEPTION(regs), *stack_bottom, addr;
     int i;
 
+    if ( guest_mode(regs) )
+        return show_guest_stack(current, regs);
+
     printk("Xen stack trace from "__OP"sp=%p:\n  ", stack);
 
     stack_bottom = _p(get_stack_dump_bottom(regs->rsp));
@@ -655,30 +662,8 @@ void show_execution_state(const struct cpu_user_regs *regs)
     unsigned long flags = console_lock_recursive_irqsave();
 
     show_registers(regs);
-
-    if ( guest_mode(regs) )
-    {
-        struct vcpu *curr = current;
-
-        if ( is_hvm_vcpu(curr) )
-        {
-            /*
-             * Stop interleaving prevention: The necessary P2M lookups
-             * involve locking, which has to occur with IRQs enabled.
-             */
-            console_unlock_recursive_irqrestore(flags);
-
-            show_hvm_stack(curr, regs);
-            return;
-        }
-
-        show_guest_stack(curr, regs);
-    }
-    else
-    {
-        show_code(regs);
-        show_stack(regs);
-    }
+    show_code(regs);
+    show_stack(regs);
 
     console_unlock_recursive_irqrestore(flags);
 }
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Fri Nov 11 05:55:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Fri, 11 Nov 2022 05:55:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.442316.696404 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otN0T-0004A8-Cy; Fri, 11 Nov 2022 05:55:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 442316.696404; Fri, 11 Nov 2022 05:55:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otN0T-0004A1-AG; Fri, 11 Nov 2022 05:55:13 +0000
Received: by outflank-mailman (input) for mailman id 442316;
 Fri, 11 Nov 2022 05:55:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otN0S-00049t-Kg
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 05:55:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otN0S-0005Gr-Jt
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 05:55:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otN0S-0000mu-Ab
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 05:55:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=xQg/1K7AQQQJ6K5beyD0GLcaTHRhAs7OXY+VEav/EaM=; b=2Z6zG8y2UXakuACM0XUNKGjGW+
	YxMiie6gvRleZgSzQDXQyPIFUYb0ZF5hLDA4vB7elh5leeGBnGlzNku7+2Knm+duN80E9PWEmTZ3S
	dpBZ3cKa5h/XmKo4ZS0JIomGF7CnkpZBNZ4ieRKNk1CRfsk+RcpbMylpX+9mvcgAwgjY=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] kexec: restore hypercall 1st arg's type
Message-Id: <E1otN0S-0000mu-Ab@xenbits.xenproject.org>
Date: Fri, 11 Nov 2022 05:55:12 +0000

commit a4180b03fffafa1868b0bcacc20198d4caef2908
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Mon Nov 7 16:09:13 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 9 20:11:49 2022 +0000

    kexec: restore hypercall 1st arg's type
    
    This reverts a small part of 7e21b25059ed ("xen: harmonize return types
    of hypercall handlers"). The change from "unsigned long" to "unsigned
    int" for the native handler function meant that previously invalid
    values became valid. While perhaps not a significant issue, strictly
    speaking that's still a change to the ABI. Don't go as far as restoring
    the compat entry point's type though: That one can't have values passed
    which don't fit in 32 bits.
    
    Note that as a side effect this fixes the invocation of
    hypercall_create_continuation(), which by mistake wasn't adjusted by the
    earlier change.
    
    Also take the opportunity and correct the respective comment in the
    public header. (The way it was it really supports that it probably was
    pointless to use "long", but that's the way the hypercall was
    introduced.)
    
    Requested-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Signed-off-by: Jan Beulich <jbeulich@suse.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/common/kexec.c           | 4 ++--
 xen/include/hypercall-defs.c | 9 ++++++---
 xen/include/public/kexec.h   | 2 +-
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/xen/common/kexec.c b/xen/common/kexec.c
index 7095651605..3ee5f05c2c 100644
--- a/xen/common/kexec.c
+++ b/xen/common/kexec.c
@@ -1213,7 +1213,7 @@ static int kexec_status(XEN_GUEST_HANDLE_PARAM(void) uarg)
     return !!test_bit(bit, &kexec_flags);
 }
 
-static int do_kexec_op_internal(unsigned int op,
+static int do_kexec_op_internal(unsigned long op,
                                 XEN_GUEST_HANDLE_PARAM(void) uarg,
                                 bool_t compat)
 {
@@ -1265,7 +1265,7 @@ static int do_kexec_op_internal(unsigned int op,
     return ret;
 }
 
-long do_kexec_op(unsigned int op, XEN_GUEST_HANDLE_PARAM(void) uarg)
+long do_kexec_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) uarg)
 {
     return do_kexec_op_internal(op, uarg, 0);
 }
diff --git a/xen/include/hypercall-defs.c b/xen/include/hypercall-defs.c
index 60cbeb18e4..45b6f969d2 100644
--- a/xen/include/hypercall-defs.c
+++ b/xen/include/hypercall-defs.c
@@ -117,9 +117,6 @@ callback_op(int cmd, const void *arg)
 #ifdef CONFIG_ARGO
 argo_op(unsigned int cmd, void *arg1, void *arg2, unsigned long arg3, unsigned long arg4)
 #endif
-#ifdef CONFIG_KEXEC
-kexec_op(unsigned int op, void *uarg)
-#endif
 #ifdef CONFIG_PV
 iret()
 nmi_op(unsigned int cmd, void *arg)
@@ -149,6 +146,9 @@ update_va_mapping_otherdomain(unsigned int va, uint32_t lo, uint32_t hi, unsigne
 #ifndef CONFIG_PV_SHIM_EXCLUSIVE
 platform_op(compat_platform_op_t *u_xenpf_op)
 #endif
+#ifdef CONFIG_KEXEC
+kexec_op(unsigned int op, void *uarg)
+#endif
 #endif /* CONFIG_COMPAT */
 
 #if defined(CONFIG_PV) || defined(CONFIG_ARM)
@@ -181,6 +181,9 @@ update_descriptor(uint64_t gaddr, seg_desc_t desc)
 update_va_mapping(unsigned long va, uint64_t val64, unsigned long flags)
 update_va_mapping_otherdomain(unsigned long va, uint64_t val64, unsigned long flags, domid_t domid)
 #endif
+#ifdef CONFIG_KEXEC
+kexec_op(unsigned long op, void *uarg)
+#endif
 #ifdef CONFIG_IOREQ_SERVER
 dm_op(domid_t domid, unsigned int nr_bufs, xen_dm_op_buf_t *bufs)
 #endif
diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h
index 3f2a118381..3cb961fdab 100644
--- a/xen/include/public/kexec.h
+++ b/xen/include/public/kexec.h
@@ -64,7 +64,7 @@
 
 /*
  * Prototype for this hypercall is:
- *  int kexec_op(int cmd, void *args)
+ *  int kexec_op(unsigned long cmd, void *args)
  * @cmd  == KEXEC_CMD_...
  *          KEXEC operation to perform
  * @args == Operation-specific extra arguments (NULL if none).
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Fri Nov 11 15:55:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Fri, 11 Nov 2022 15:55:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.442652.697047 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otWMy-0003E3-1N; Fri, 11 Nov 2022 15:55:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 442652.697047; Fri, 11 Nov 2022 15:55:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otWMx-0003Dv-Ut; Fri, 11 Nov 2022 15:55:03 +0000
Received: by outflank-mailman (input) for mailman id 442652;
 Fri, 11 Nov 2022 15:55:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otWMw-0003Dp-4o
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 15:55:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otWMw-0002ey-16
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 15:55:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otWMv-0001OF-Vq
 for xen-changelog@lists.xenproject.org; Fri, 11 Nov 2022 15:55:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=K519qN3N4IJ83BU12E3SUqt8bY4hk4HEzPLWqrr+sRk=; b=hqm7de+AlOLDnPai5YzErq0eZm
	duP8untdPY10UB9b0HvbajsQtjw22jAxRzVIfpTfoxqVVOAyvkBdnZXcSFNBcLGa8yIUWwSfgt+yG
	QsRT0jp5KpAcgZdofDt4uWcORG/37CKy/TogUeBuf3hEamFEc179pMhWDkSWqc8sxFiU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] arm: fix Kconfig symbol dependency on arm features
Message-Id: <E1otWMv-0001OF-Vq@xenbits.xenproject.org>
Date: Fri, 11 Nov 2022 15:55:01 +0000

commit 08c6f57cfebad4046dabc05092b4a27c61a39980
Author:     Luca Fancellu <luca.fancellu@arm.com>
AuthorDate: Wed Nov 9 14:04:20 2022 +0000
Commit:     Julien Grall <jgrall@amazon.com>
CommitDate: Thu Nov 10 19:04:40 2022 +0000

    arm: fix Kconfig symbol dependency on arm features
    
    The commit 3c2a14ea81c7 is introducing some unsupported arm features
    that by default are disabled and are used for the cpufeature.c code.
    
    As they are disabled by default, a typo in the Kconfig symbol they
    depend on has landed in the codebase unnoticed, instead of depending
    on ARM64 which does not exist, fix the code to depend on ARM_64 that
    is the intended symbol.
    
    Fixes: 3c2a14ea81c7 ("arm: Define kconfig symbols used by arm64 cpufeatures")
    Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
    Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
---
 xen/arch/arm/Kconfig | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 1fe5faf847..52a05f704d 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -105,28 +105,28 @@ config HARDEN_BRANCH_PREDICTOR
 
 config ARM64_PTR_AUTH
 	def_bool n
-	depends on ARM64
+	depends on ARM_64
 	help
 	  Pointer authentication support.
 	  This feature is not supported in Xen.
 
 config ARM64_SVE
 	def_bool n
-	depends on ARM64
+	depends on ARM_64
 	help
 	  Scalar Vector Extension support.
 	  This feature is not supported in Xen.
 
 config ARM64_MTE
 	def_bool n
-	depends on ARM64
+	depends on ARM_64
 	help
 	  Memory Tagging Extension support.
 	  This feature is not supported in Xen.
 
 config ARM64_BTI
 	def_bool n
-	depends on ARM64
+	depends on ARM_64
 	help
 	  Branch Target Identification support.
 	  This feature is not supported in Xen.
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Sat Nov 12 23:22:11 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Sat, 12 Nov 2022 23:22:11 +0000
Received: from list by lists.xenproject.org with outflank-mailman.442898.697307 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otzp5-00064n-9N; Sat, 12 Nov 2022 23:22:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 442898.697307; Sat, 12 Nov 2022 23:22:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otzp5-00064f-5Y; Sat, 12 Nov 2022 23:22:03 +0000
Received: by outflank-mailman (input) for mailman id 442898;
 Sat, 12 Nov 2022 23:22:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzp4-00064Z-BL
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzp4-0003BI-6J
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzp4-0006Xt-53
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=dbo3LrHs1NwemEWUbfOu3gXCMYyqxUrxRBWQt7wsUzg=; b=ZzOIC8Y+LoktJhaivj5d7/zs1b
	uqd+1sMA0gjVVGfG5ep+tmVb3dttT15CO7FaQVSCp5qnr+3iPdlW1VUOif+GuF32Axle2qej05i4Z
	kfv6c9v3lgrrnirHILBGWEpv5ViXd8ZLWMumXfw9Z3P655XckDIg5vbos9yDyi8liqHE=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] Add licenses under LICENSES
Message-Id: <E1otzp4-0006Xt-53@xenbits.xenproject.org>
Date: Sat, 12 Nov 2022 23:22:02 +0000

commit 63ca22f9207aadebe6aaeab4dc21b1fcd9e7795a
Author:     Stefano Stabellini <stefano.stabellini@amd.com>
AuthorDate: Wed Oct 12 17:56:45 2022 -0700
Commit:     Stefano Stabellini <stefano.stabellini@amd.com>
CommitDate: Fri Nov 11 12:18:01 2022 -0800

    Add licenses under LICENSES
    
    Add the individual licenses under a new top-level directory named
    "LICENSES". Each license file includes its related SPDX tags.
    
    Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 LICENSES/BSD-2-Clause       |  32 +++
 LICENSES/BSD-3-Clause       |  36 ++++
 LICENSES/BSD-3-Clause-Clear |  41 ++++
 LICENSES/GPL-2.0            | 359 +++++++++++++++++++++++++++++++
 LICENSES/LGPL-2.0           | 487 ++++++++++++++++++++++++++++++++++++++++++
 LICENSES/LGPL-2.1           | 503 ++++++++++++++++++++++++++++++++++++++++++++
 LICENSES/MIT                |  30 +++
 7 files changed, 1488 insertions(+)

diff --git a/LICENSES/BSD-2-Clause b/LICENSES/BSD-2-Clause
new file mode 100644
index 0000000000..da366e2ce5
--- /dev/null
+++ b/LICENSES/BSD-2-Clause
@@ -0,0 +1,32 @@
+Valid-License-Identifier: BSD-2-Clause
+SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html
+Usage-Guide:
+  To use the BSD 2-clause "Simplified" License put the following SPDX
+  tag/value pair into a comment according to the placement guidelines in
+  the licensing rules documentation:
+    SPDX-License-Identifier: BSD-2-Clause
+License-Text:
+
+Copyright (c) <year> <owner> . All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/LICENSES/BSD-3-Clause b/LICENSES/BSD-3-Clause
new file mode 100644
index 0000000000..34c7f057c8
--- /dev/null
+++ b/LICENSES/BSD-3-Clause
@@ -0,0 +1,36 @@
+Valid-License-Identifier: BSD-3-Clause
+SPDX-URL: https://spdx.org/licenses/BSD-3-Clause.html
+Usage-Guide:
+  To use the BSD 3-clause "New" or "Revised" License put the following SPDX
+  tag/value pair into a comment according to the placement guidelines in
+  the licensing rules documentation:
+    SPDX-License-Identifier: BSD-3-Clause
+License-Text:
+
+Copyright (c) <year> <owner> . All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/LICENSES/BSD-3-Clause-Clear b/LICENSES/BSD-3-Clause-Clear
new file mode 100644
index 0000000000..e53b56092b
--- /dev/null
+++ b/LICENSES/BSD-3-Clause-Clear
@@ -0,0 +1,41 @@
+Valid-License-Identifier: BSD-3-Clause-Clear
+SPDX-URL: https://spdx.org/licenses/BSD-3-Clause-Clear.html
+Usage-Guide:
+  To use the BSD 3-clause "Clear" License put the following SPDX
+  tag/value pair into a comment according to the placement guidelines in
+  the licensing rules documentation:
+    SPDX-License-Identifier: BSD-3-Clause-Clear
+License-Text:
+
+The Clear BSD License
+
+Copyright (c) [xxxx]-[xxxx] [Owner Organization]
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted (subject to the limitations in the disclaimer
+below) provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+ * Neither the name of [Owner Organization] nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
+THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/LICENSES/GPL-2.0 b/LICENSES/GPL-2.0
new file mode 100644
index 0000000000..ff0812fd89
--- /dev/null
+++ b/LICENSES/GPL-2.0
@@ -0,0 +1,359 @@
+Valid-License-Identifier: GPL-2.0
+Valid-License-Identifier: GPL-2.0-only
+Valid-License-Identifier: GPL-2.0+
+Valid-License-Identifier: GPL-2.0-or-later
+SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
+Usage-Guide:
+  To use this license in source code, put one of the following SPDX
+  tag/value pairs into a comment according to the placement
+  guidelines in the licensing rules documentation.
+  For 'GNU General Public License (GPL) version 2 only' use:
+    SPDX-License-Identifier: GPL-2.0
+  or
+    SPDX-License-Identifier: GPL-2.0-only
+  For 'GNU General Public License (GPL) version 2 or any later version' use:
+    SPDX-License-Identifier: GPL-2.0+
+  or
+    SPDX-License-Identifier: GPL-2.0-or-later
+License-Text:
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/LICENSES/LGPL-2.0 b/LICENSES/LGPL-2.0
new file mode 100644
index 0000000000..957d798fe0
--- /dev/null
+++ b/LICENSES/LGPL-2.0
@@ -0,0 +1,487 @@
+Valid-License-Identifier: LGPL-2.0
+Valid-License-Identifier: LGPL-2.0+
+SPDX-URL: https://spdx.org/licenses/LGPL-2.0.html
+Usage-Guide:
+  To use this license in source code, put one of the following SPDX
+  tag/value pairs into a comment according to the placement
+  guidelines in the licensing rules documentation.
+  For 'GNU Library General Public License (LGPL) version 2.0 only' use:
+    SPDX-License-Identifier: LGPL-2.0
+  For 'GNU Library General Public License (LGPL) version 2.0 or any later
+  version' use:
+    SPDX-License-Identifier: LGPL-2.0+
+License-Text:
+
+GNU LIBRARY GENERAL PUBLIC LICENSE
+Version 2, June 1991
+
+Copyright (C) 1991 Free Software Foundation, Inc.
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is numbered 2
+because it goes with version 2 of the ordinary GPL.]
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public Licenses are
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users.
+
+This license, the Library General Public License, applies to some specially
+designated Free Software Foundation software, and to any other libraries
+whose authors decide to use it. You can use it for your libraries, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom
+to distribute copies of free software (and charge for this service if you
+wish), that you receive source code or can get it if you want it, that you
+can change the software or use pieces of it in new free programs; and that
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you
+distribute copies of the library, or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis or for
+a fee, you must give the recipients all the rights that we gave you. You
+must make sure that they, too, receive or can get the source code. If you
+link a program with the library, you must provide complete object files to
+the recipients so that they can relink them with the library, after making
+changes to the library and recompiling it. And you must show them these
+terms so they know their rights.
+
+Our method of protecting your rights has two steps: (1) copyright the
+library, and (2) offer you this license which gives you legal permission to
+copy, distribute and/or modify the library.
+
+Also, for each distributor's protection, we want to make certain that
+everyone understands that there is no warranty for this free library. If
+the library is modified by someone else and passed on, we want its
+recipients to know that what they have is not the original version, so that
+any problems introduced by others will not reflect on the original authors'
+reputations.
+
+Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that companies distributing free software will
+individually obtain patent licenses, thus in effect transforming the
+program into proprietary software. To prevent this, we have made it clear
+that any patent must be licensed for everyone's free use or not licensed at
+all.
+
+Most GNU software, including some libraries, is covered by the ordinary GNU
+General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+Because of this blurred distinction, using the ordinary General Public
+License for libraries did not effectively promote software sharing, because
+most developers did not use the libraries. We concluded that weaker
+conditions might promote sharing better.
+
+However, unrestricted linking of non-free programs would deprive the users
+of those programs of all benefit from the free status of the libraries
+themselves. This Library General Public License is intended to permit
+developers of non-free programs to use free libraries, while preserving
+your freedom as a user of such programs to change the free libraries that
+are incorporated in them. (We have not seen how to achieve this as regards
+changes in header files, but we have achieved it as regards changes in the
+actual functions of the Library.) The hope is that this will lead to faster
+development of free libraries.
+
+The precise terms and conditions for copying, distribution and modification
+follow. Pay close attention to the difference between a "work based on the
+library" and a "work that uses the library". The former contains code
+derived from the library, while the latter only works together with the
+library.
+
+Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License Agreement applies to any software library which contains a
+   notice placed by the copyright holder or other authorized party saying
+   it may be distributed under the terms of this Library General Public
+   License (also called "this License"). Each licensee is addressed as
+   "you".
+
+   A "library" means a collection of software functions and/or data
+   prepared so as to be conveniently linked with application programs
+   (which use some of those functions and data) to form executables.
+
+   The "Library", below, refers to any such software library or work which
+   has been distributed under these terms. A "work based on the Library"
+   means either the Library or any derivative work under copyright law:
+   that is to say, a work containing the Library or a portion of it, either
+   verbatim or with modifications and/or translated straightforwardly into
+   another language. (Hereinafter, translation is included without
+   limitation in the term "modification".)
+
+   "Source code" for a work means the preferred form of the work for making
+   modifications to it. For a library, complete source code means all the
+   source code for all modules it contains, plus any associated interface
+   definition files, plus the scripts used to control compilation and
+   installation of the library.
+
+   Activities other than copying, distribution and modification are not
+   covered by this License; they are outside its scope. The act of running
+   a program using the Library is not restricted, and output from such a
+   program is covered only if its contents constitute a work based on the
+   Library (independent of the use of the Library in a tool for writing
+   it). Whether that is true depends on what the Library does and what the
+   program that uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's complete
+   source code as you receive it, in any medium, provided that you
+   conspicuously and appropriately publish on each copy an appropriate
+   copyright notice and disclaimer of warranty; keep intact all the notices
+   that refer to this License and to the absence of any warranty; and
+   distribute a copy of this License along with the Library.
+
+   You may charge a fee for the physical act of transferring a copy, and
+   you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Library or any portion of it,
+   thus forming a work based on the Library, and copy and distribute such
+   modifications or work under the terms of Section 1 above, provided that
+   you also meet all of these conditions:
+
+   a) The modified work must itself be a software library.
+
+   b) You must cause the files modified to carry prominent notices stating
+      that you changed the files and the date of any change.
+
+   c) You must cause the whole of the work to be licensed at no charge to
+      all third parties under the terms of this License.
+
+   d) If a facility in the modified Library refers to a function or a table
+      of data to be supplied by an application program that uses the
+      facility, other than as an argument passed when the facility is
+      invoked, then you must make a good faith effort to ensure that, in
+      the event an application does not supply such function or table, the
+      facility still operates, and performs whatever part of its purpose
+      remains meaningful.
+
+   (For example, a function in a library to compute square roots has a
+   purpose that is entirely well-defined independent of the
+   application. Therefore, Subsection 2d requires that any
+   application-supplied function or table used by this function must be
+   optional: if the application does not supply it, the square root
+   function must still compute square roots.)
+
+   These requirements apply to the modified work as a whole. If
+   identifiable sections of that work are not derived from the Library, and
+   can be reasonably considered independent and separate works in
+   themselves, then this License, and its terms, do not apply to those
+   sections when you distribute them as separate works. But when you
+   distribute the same sections as part of a whole which is a work based on
+   the Library, the distribution of the whole must be on the terms of this
+   License, whose permissions for other licensees extend to the entire
+   whole, and thus to each and every part regardless of who wrote it.
+
+   Thus, it is not the intent of this section to claim rights or contest
+   your rights to work written entirely by you; rather, the intent is to
+   exercise the right to control the distribution of derivative or
+   collective works based on the Library.
+
+   In addition, mere aggregation of another work not based on the Library
+   with the Library (or with a work based on the Library) on a volume of a
+   storage or distribution medium does not bring the other work under the
+   scope of this License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public
+   License instead of this License to a given copy of the Library. To do
+   this, you must alter all the notices that refer to this License, so that
+   they refer to the ordinary GNU General Public License, version 2,
+   instead of to this License. (If a newer version than version 2 of the
+   ordinary GNU General Public License has appeared, then you can specify
+   that version instead if you wish.) Do not make any other change in these
+   notices.
+
+   Once this change is made in a given copy, it is irreversible for that
+   copy, so the ordinary GNU General Public License applies to all
+   subsequent copies and derivative works made from that copy.
+
+   This option is useful when you wish to copy part of the code of the
+   Library into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative of
+   it, under Section 2) in object code or executable form under the terms
+   of Sections 1 and 2 above provided that you accompany it with the
+   complete corresponding machine-readable source code, which must be
+   distributed under the terms of Sections 1 and 2 above on a medium
+   customarily used for software interchange.
+
+   If distribution of object code is made by offering access to copy from a
+   designated place, then offering equivalent access to copy the source
+   code from the same place satisfies the requirement to distribute the
+   source code, even though third parties are not compelled to copy the
+   source along with the object code.
+
+5. A program that contains no derivative of any portion of the Library, but
+   is designed to work with the Library by being compiled or linked with
+   it, is called a "work that uses the Library". Such a work, in isolation,
+   is not a derivative work of the Library, and therefore falls outside the
+   scope of this License.
+
+   However, linking a "work that uses the Library" with the Library creates
+   an executable that is a derivative of the Library (because it contains
+   portions of the Library), rather than a "work that uses the
+   library". The executable is therefore covered by this License. Section 6
+   states terms for distribution of such executables.
+
+   When a "work that uses the Library" uses material from a header file
+   that is part of the Library, the object code for the work may be a
+   derivative work of the Library even though the source code is
+   not. Whether this is true is especially significant if the work can be
+   linked without the Library, or if the work is itself a library. The
+   threshold for this to be true is not precisely defined by law.
+
+   If such an object file uses only numerical parameters, data structure
+   layouts and accessors, and small macros and small inline functions (ten
+   lines or less in length), then the use of the object file is
+   unrestricted, regardless of whether it is legally a derivative
+   work. (Executables containing this object code plus portions of the
+   Library will still fall under Section 6.)
+
+   Otherwise, if the work is a derivative of the Library, you may
+   distribute the object code for the work under the terms of Section
+   6. Any executables containing that work also fall under Section 6,
+   whether or not they are linked directly with the Library itself.
+
+6. As an exception to the Sections above, you may also compile or link a
+   "work that uses the Library" with the Library to produce a work
+   containing portions of the Library, and distribute that work under terms
+   of your choice, provided that the terms permit modification of the work
+   for the customer's own use and reverse engineering for debugging such
+   modifications.
+
+   You must give prominent notice with each copy of the work that the
+   Library is used in it and that the Library and its use are covered by
+   this License. You must supply a copy of this License. If the work during
+   execution displays copyright notices, you must include the copyright
+   notice for the Library among them, as well as a reference directing the
+   user to the copy of this License. Also, you must do one of these things:
+
+   a) Accompany the work with the complete corresponding machine-readable
+      source code for the Library including whatever changes were used in
+      the work (which must be distributed under Sections 1 and 2 above);
+      and, if the work is an executable linked with the Library, with the
+      complete machine-readable "work that uses the Library", as object
+      code and/or source code, so that the user can modify the Library and
+      then relink to produce a modified executable containing the modified
+      Library. (It is understood that the user who changes the contents of
+      definitions files in the Library will not necessarily be able to
+      recompile the application to use the modified definitions.)
+
+   b) Accompany the work with a written offer, valid for at least three
+      years, to give the same user the materials specified in Subsection
+      6a, above, for a charge no more than the cost of performing this
+      distribution.
+
+   c) If distribution of the work is made by offering access to copy from a
+      designated place, offer equivalent access to copy the above specified
+      materials from the same place.
+
+   d) Verify that the user has already received a copy of these materials
+      or that you have already sent this user a copy.
+
+   For an executable, the required form of the "work that uses the Library"
+   must include any data and utility programs needed for reproducing the
+   executable from it. However, as a special exception, the source code
+   distributed need not include anything that is normally distributed (in
+   either source or binary form) with the major components (compiler,
+   kernel, and so on) of the operating system on which the executable runs,
+   unless that component itself accompanies the executable.
+
+   It may happen that this requirement contradicts the license restrictions
+   of other proprietary libraries that do not normally accompany the
+   operating system. Such a contradiction means you cannot use both them
+   and the Library together in an executable that you distribute.
+
+7. You may place library facilities that are a work based on the Library
+   side-by-side in a single library together with other library facilities
+   not covered by this License, and distribute such a combined library,
+   provided that the separate distribution of the work based on the Library
+   and of the other library facilities is otherwise permitted, and provided
+   that you do these two things:
+
+   a) Accompany the combined library with a copy of the same work based on
+      the Library, uncombined with any other library facilities. This must
+      be distributed under the terms of the Sections above.
+
+   b) Give prominent notice with the combined library of the fact that part
+      of it is a work based on the Library, and explaining where to find
+      the accompanying uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the
+   Library except as expressly provided under this License. Any attempt
+   otherwise to copy, modify, sublicense, link with, or distribute the
+   Library is void, and will automatically terminate your rights under this
+   License. However, parties who have received copies, or rights, from you
+   under this License will not have their licenses terminated so long as
+   such parties remain in full compliance.
+
+9. You are not required to accept this License, since you have not signed
+   it. However, nothing else grants you permission to modify or distribute
+   the Library or its derivative works. These actions are prohibited by law
+   if you do not accept this License. Therefore, by modifying or
+   distributing the Library (or any work based on the Library), you
+   indicate your acceptance of this License to do so, and all its terms and
+   conditions for copying, distributing or modifying the Library or works
+   based on it.
+
+10. Each time you redistribute the Library (or any work based on the
+    Library), the recipient automatically receives a license from the
+    original licensor to copy, distribute, link with or modify the Library
+    subject to these terms and conditions. You may not impose any further
+    restrictions on the recipients' exercise of the rights granted
+    herein. You are not responsible for enforcing compliance by third
+    parties to this License.
+
+11. If, as a consequence of a court judgment or allegation of patent
+    infringement or for any other reason (not limited to patent issues),
+    conditions are imposed on you (whether by court order, agreement or
+    otherwise) that contradict the conditions of this License, they do not
+    excuse you from the conditions of this License. If you cannot
+    distribute so as to satisfy simultaneously your obligations under this
+    License and any other pertinent obligations, then as a consequence you
+    may not distribute the Library at all. For example, if a patent license
+    would not permit royalty-free redistribution of the Library by all
+    those who receive copies directly or indirectly through you, then the
+    only way you could satisfy both it and this License would be to refrain
+    entirely from distribution of the Library.
+
+    If any portion of this section is held invalid or unenforceable under
+    any particular circumstance, the balance of the section is intended to
+    apply, and the section as a whole is intended to apply in other
+    circumstances.
+
+    It is not the purpose of this section to induce you to infringe any
+    patents or other property right claims or to contest validity of any
+    such claims; this section has the sole purpose of protecting the
+    integrity of the free software distribution system which is implemented
+    by public license practices. Many people have made generous
+    contributions to the wide range of software distributed through that
+    system in reliance on consistent application of that system; it is up
+    to the author/donor to decide if he or she is willing to distribute
+    software through any other system and a licensee cannot impose that
+    choice.
+
+    This section is intended to make thoroughly clear what is believed to
+    be a consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in certain
+    countries either by patents or by copyrighted interfaces, the original
+    copyright holder who places the Library under this License may add an
+    explicit geographical distribution limitation excluding those
+    countries, so that distribution is permitted only in or among countries
+    not thus excluded. In such case, this License incorporates the
+    limitation as if written in the body of this License.
+
+13. The Free Software Foundation may publish revised and/or new versions of
+    the Library General Public License from time to time. Such new versions
+    will be similar in spirit to the present version, but may differ in
+    detail to address new problems or concerns.
+
+    Each version is given a distinguishing version number. If the Library
+    specifies a version number of this License which applies to it and "any
+    later version", you have the option of following the terms and
+    conditions either of that version or of any later version published by
+    the Free Software Foundation. If the Library does not specify a license
+    version number, you may choose any version ever published by the Free
+    Software Foundation.
+
+14. If you wish to incorporate parts of the Library into other free
+    programs whose distribution conditions are incompatible with these,
+    write to the author to ask for permission. For software which is
+    copyrighted by the Free Software Foundation, write to the Free Software
+    Foundation; we sometimes make exceptions for this. Our decision will be
+    guided by the two goals of preserving the free status of all
+    derivatives of our free software and of promoting the sharing and reuse
+    of software generally.
+
+NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+    FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+    PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH
+    YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+    NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+    REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY
+    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+    THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR
+    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Libraries
+
+If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+one line to give the library's name and an idea of what it does.
+Copyright (C) year name of author
+
+This library is free software; you can redistribute it and/or modify it
+under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+This library is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; if not, write to the Free Software Foundation,
+Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in
+the library `Frob' (a library for tweaking knobs) written
+by James Random Hacker.
+
+signature of Ty Coon, 1 April 1990
+Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/LICENSES/LGPL-2.1 b/LICENSES/LGPL-2.1
new file mode 100644
index 0000000000..27bb4342a3
--- /dev/null
+++ b/LICENSES/LGPL-2.1
@@ -0,0 +1,503 @@
+Valid-License-Identifier: LGPL-2.1
+Valid-License-Identifier: LGPL-2.1+
+SPDX-URL: https://spdx.org/licenses/LGPL-2.1.html
+Usage-Guide:
+  To use this license in source code, put one of the following SPDX
+  tag/value pairs into a comment according to the placement
+  guidelines in the licensing rules documentation.
+  For 'GNU Lesser General Public License (LGPL) version 2.1 only' use:
+    SPDX-License-Identifier: LGPL-2.1
+  For 'GNU Lesser General Public License (LGPL) version 2.1 or any later
+  version' use:
+    SPDX-License-Identifier: LGPL-2.1+
+License-Text:
+
+GNU LESSER GENERAL PUBLIC LICENSE
+Version 2.1, February 1999
+
+Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts as
+the successor of the GNU Library Public License, version 2, hence the
+version number 2.1.]
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public Licenses are
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users.
+
+This license, the Lesser General Public License, applies to some specially
+designated software packages--typically libraries--of the Free Software
+Foundation and other authors who decide to use it. You can use it too, but
+we suggest you first think carefully about whether this license or the
+ordinary General Public License is the better strategy to use in any
+particular case, based on the explanations below.
+
+When we speak of free software, we are referring to freedom of use, not
+price. Our General Public Licenses are designed to make sure that you have
+the freedom to distribute copies of free software (and charge for this
+service if you wish); that you receive source code or can get it if you
+want it; that you can change the software and use pieces of it in new free
+programs; and that you are informed that you can do these things.
+
+To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for you if
+you distribute copies of the library or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis or for
+a fee, you must give the recipients all the rights that we gave you. You
+must make sure that they, too, receive or can get the source code. If you
+link other code with the library, you must provide complete object files to
+the recipients, so that they can relink them with the library after making
+changes to the library and recompiling it. And you must show them these
+terms so they know their rights.
+
+We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+To protect each distributor, we want to make it very clear that there is no
+warranty for the free library. Also, if the library is modified by someone
+else and passed on, the recipients should know that what they have is not
+the original version, so that the original author's reputation will not be
+affected by problems that might be introduced by others.
+
+Finally, software patents pose a constant threat to the existence of any
+free program. We wish to make sure that a company cannot effectively
+restrict the users of a free program by obtaining a restrictive license
+from a patent holder. Therefore, we insist that any patent license obtained
+for a version of the library must be consistent with the full freedom of
+use specified in this license.
+
+Most GNU software, including some libraries, is covered by the ordinary GNU
+General Public License. This license, the GNU Lesser General Public
+License, applies to certain designated libraries, and is quite different
+from the ordinary General Public License. We use this license for certain
+libraries in order to permit linking those libraries into non-free
+programs.
+
+When a program is linked with a library, whether statically or using a
+shared library, the combination of the two is legally speaking a combined
+work, a derivative of the original library. The ordinary General Public
+License therefore permits such linking only if the entire combination fits
+its criteria of freedom. The Lesser General Public License permits more lax
+criteria for linking other code with the library.
+
+We call this license the "Lesser" General Public License because it does
+Less to protect the user's freedom than the ordinary General Public
+License. It also provides other free software developers Less of an
+advantage over competing non-free programs. These disadvantages are the
+reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+For example, on rare occasions, there may be a special need to encourage
+the widest possible use of a certain library, so that it becomes a de-facto
+standard. To achieve this, non-free programs must be allowed to use the
+library. A more frequent case is that a free library does the same job as
+widely used non-free libraries. In this case, there is little to gain by
+limiting the free library to free software only, so we use the Lesser
+General Public License.
+
+In other cases, permission to use a particular library in non-free programs
+enables a greater number of people to use a large body of free
+software. For example, permission to use the GNU C Library in non-free
+programs enables many more people to use the whole GNU operating system, as
+well as its variant, the GNU/Linux operating system.
+
+Although the Lesser General Public License is Less protective of the users'
+freedom, it does ensure that the user of a program that is linked with the
+Library has the freedom and the wherewithal to run that program using a
+modified version of the Library.
+
+The precise terms and conditions for copying, distribution and modification
+follow. Pay close attention to the difference between a "work based on the
+library" and a "work that uses the library". The former contains code
+derived from the library, whereas the latter must be combined with the
+library in order to run.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License Agreement applies to any software library or other program
+   which contains a notice placed by the copyright holder or other
+   authorized party saying it may be distributed under the terms of this
+   Lesser General Public License (also called "this License"). Each
+   licensee is addressed as "you".
+
+   A "library" means a collection of software functions and/or data
+   prepared so as to be conveniently linked with application programs
+   (which use some of those functions and data) to form executables.
+
+   The "Library", below, refers to any such software library or work which
+   has been distributed under these terms. A "work based on the Library"
+   means either the Library or any derivative work under copyright law:
+   that is to say, a work containing the Library or a portion of it, either
+   verbatim or with modifications and/or translated straightforwardly into
+   another language. (Hereinafter, translation is included without
+   limitation in the term "modification".)
+
+   "Source code" for a work means the preferred form of the work for making
+   modifications to it. For a library, complete source code means all the
+   source code for all modules it contains, plus any associated interface
+   definition files, plus the scripts used to control compilation and
+   installation of the library.
+
+    Activities other than copying, distribution and modification are not
+    covered by this License; they are outside its scope. The act of running
+    a program using the Library is not restricted, and output from such a
+    program is covered only if its contents constitute a work based on the
+    Library (independent of the use of the Library in a tool for writing
+    it). Whether that is true depends on what the Library does and what the
+    program that uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's complete
+   source code as you receive it, in any medium, provided that you
+   conspicuously and appropriately publish on each copy an appropriate
+   copyright notice and disclaimer of warranty; keep intact all the notices
+   that refer to this License and to the absence of any warranty; and
+   distribute a copy of this License along with the Library.
+
+   You may charge a fee for the physical act of transferring a copy, and
+   you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Library or any portion of it,
+   thus forming a work based on the Library, and copy and distribute such
+   modifications or work under the terms of Section 1 above, provided that
+   you also meet all of these conditions:
+
+   a) The modified work must itself be a software library.
+
+   b) You must cause the files modified to carry prominent notices stating
+      that you changed the files and the date of any change.
+
+   c) You must cause the whole of the work to be licensed at no charge to
+      all third parties under the terms of this License.
+
+   d) If a facility in the modified Library refers to a function or a table
+      of data to be supplied by an application program that uses the
+      facility, other than as an argument passed when the facility is
+      invoked, then you must make a good faith effort to ensure that, in
+      the event an application does not supply such function or table, the
+      facility still operates, and performs whatever part of its purpose
+      remains meaningful.
+
+   (For example, a function in a library to compute square roots has a
+    purpose that is entirely well-defined independent of the
+    application. Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must be
+    optional: if the application does not supply it, the square root
+    function must still compute square roots.)
+
+   These requirements apply to the modified work as a whole. If
+   identifiable sections of that work are not derived from the Library, and
+   can be reasonably considered independent and separate works in
+   themselves, then this License, and its terms, do not apply to those
+   sections when you distribute them as separate works. But when you
+   distribute the same sections as part of a whole which is a work based on
+   the Library, the distribution of the whole must be on the terms of this
+   License, whose permissions for other licensees extend to the entire
+   whole, and thus to each and every part regardless of who wrote it.
+
+   Thus, it is not the intent of this section to claim rights or contest
+   your rights to work written entirely by you; rather, the intent is to
+   exercise the right to control the distribution of derivative or
+   collective works based on the Library.
+
+   In addition, mere aggregation of another work not based on the Library
+   with the Library (or with a work based on the Library) on a volume of a
+   storage or distribution medium does not bring the other work under the
+   scope of this License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public
+   License instead of this License to a given copy of the Library. To do
+   this, you must alter all the notices that refer to this License, so that
+   they refer to the ordinary GNU General Public License, version 2,
+   instead of to this License. (If a newer version than version 2 of the
+   ordinary GNU General Public License has appeared, then you can specify
+   that version instead if you wish.) Do not make any other change in these
+   notices.
+
+   Once this change is made in a given copy, it is irreversible for that
+   copy, so the ordinary GNU General Public License applies to all
+   subsequent copies and derivative works made from that copy.
+
+   This option is useful when you wish to copy part of the code of the
+   Library into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative of
+   it, under Section 2) in object code or executable form under the terms
+   of Sections 1 and 2 above provided that you accompany it with the
+   complete corresponding machine-readable source code, which must be
+   distributed under the terms of Sections 1 and 2 above on a medium
+   customarily used for software interchange.
+
+   If distribution of object code is made by offering access to copy from a
+   designated place, then offering equivalent access to copy the source
+   code from the same place satisfies the requirement to distribute the
+   source code, even though third parties are not compelled to copy the
+   source along with the object code.
+
+5. A program that contains no derivative of any portion of the Library, but
+   is designed to work with the Library by being compiled or linked with
+   it, is called a "work that uses the Library". Such a work, in isolation,
+   is not a derivative work of the Library, and therefore falls outside the
+   scope of this License.
+
+   However, linking a "work that uses the Library" with the Library creates
+   an executable that is a derivative of the Library (because it contains
+   portions of the Library), rather than a "work that uses the
+   library". The executable is therefore covered by this License. Section 6
+   states terms for distribution of such executables.
+
+   When a "work that uses the Library" uses material from a header file
+   that is part of the Library, the object code for the work may be a
+   derivative work of the Library even though the source code is
+   not. Whether this is true is especially significant if the work can be
+   linked without the Library, or if the work is itself a library. The
+   threshold for this to be true is not precisely defined by law.
+
+   If such an object file uses only numerical parameters, data structure
+   layouts and accessors, and small macros and small inline functions (ten
+   lines or less in length), then the use of the object file is
+   unrestricted, regardless of whether it is legally a derivative
+   work. (Executables containing this object code plus portions of the
+   Library will still fall under Section 6.)
+
+   Otherwise, if the work is a derivative of the Library, you may
+   distribute the object code for the work under the terms of Section
+   6. Any executables containing that work also fall under Section 6,
+   whether or not they are linked directly with the Library itself.
+
+6. As an exception to the Sections above, you may also combine or link a
+   "work that uses the Library" with the Library to produce a work
+   containing portions of the Library, and distribute that work under terms
+   of your choice, provided that the terms permit modification of the work
+   for the customer's own use and reverse engineering for debugging such
+   modifications.
+
+   You must give prominent notice with each copy of the work that the
+   Library is used in it and that the Library and its use are covered by
+   this License. You must supply a copy of this License. If the work during
+   execution displays copyright notices, you must include the copyright
+   notice for the Library among them, as well as a reference directing the
+   user to the copy of this License. Also, you must do one of these things:
+
+   a) Accompany the work with the complete corresponding machine-readable
+      source code for the Library including whatever changes were used in
+      the work (which must be distributed under Sections 1 and 2 above);
+      and, if the work is an executable linked with the Library, with the
+      complete machine-readable "work that uses the Library", as object
+      code and/or source code, so that the user can modify the Library and
+      then relink to produce a modified executable containing the modified
+      Library. (It is understood that the user who changes the contents of
+      definitions files in the Library will not necessarily be able to
+      recompile the application to use the modified definitions.)
+
+   b) Use a suitable shared library mechanism for linking with the
+      Library. A suitable mechanism is one that (1) uses at run time a copy
+      of the library already present on the user's computer system, rather
+      than copying library functions into the executable, and (2) will
+      operate properly with a modified version of the library, if the user
+      installs one, as long as the modified version is interface-compatible
+      with the version that the work was made with.
+
+   c) Accompany the work with a written offer, valid for at least three
+      years, to give the same user the materials specified in Subsection
+      6a, above, for a charge no more than the cost of performing this
+      distribution.
+
+   d) If distribution of the work is made by offering access to copy from a
+      designated place, offer equivalent access to copy the above specified
+      materials from the same place.
+
+   e) Verify that the user has already received a copy of these materials
+      or that you have already sent this user a copy.
+
+   For an executable, the required form of the "work that uses the Library"
+   must include any data and utility programs needed for reproducing the
+   executable from it. However, as a special exception, the materials to be
+   distributed need not include anything that is normally distributed (in
+   either source or binary form) with the major components (compiler,
+   kernel, and so on) of the operating system on which the executable runs,
+   unless that component itself accompanies the executable.
+
+   It may happen that this requirement contradicts the license restrictions
+   of other proprietary libraries that do not normally accompany the
+   operating system. Such a contradiction means you cannot use both them
+   and the Library together in an executable that you distribute.
+
+7. You may place library facilities that are a work based on the Library
+   side-by-side in a single library together with other library facilities
+   not covered by this License, and distribute such a combined library,
+   provided that the separate distribution of the work based on the Library
+   and of the other library facilities is otherwise permitted, and provided
+   that you do these two things:
+
+   a) Accompany the combined library with a copy of the same work based on
+      the Library, uncombined with any other library facilities. This must
+      be distributed under the terms of the Sections above.
+
+   b) Give prominent notice with the combined library of the fact that part
+      of it is a work based on the Library, and explaining where to find
+      the accompanying uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the
+   Library except as expressly provided under this License. Any attempt
+   otherwise to copy, modify, sublicense, link with, or distribute the
+   Library is void, and will automatically terminate your rights under this
+   License. However, parties who have received copies, or rights, from you
+   under this License will not have their licenses terminated so long as
+   such parties remain in full compliance.
+
+9. You are not required to accept this License, since you have not signed
+   it. However, nothing else grants you permission to modify or distribute
+   the Library or its derivative works. These actions are prohibited by law
+   if you do not accept this License. Therefore, by modifying or
+   distributing the Library (or any work based on the Library), you
+   indicate your acceptance of this License to do so, and all its terms and
+   conditions for copying, distributing or modifying the Library or works
+   based on it.
+
+10. Each time you redistribute the Library (or any work based on the
+    Library), the recipient automatically receives a license from the
+    original licensor to copy, distribute, link with or modify the Library
+    subject to these terms and conditions. You may not impose any further
+    restrictions on the recipients' exercise of the rights granted
+    herein. You are not responsible for enforcing compliance by third
+    parties with this License.
+
+11. If, as a consequence of a court judgment or allegation of patent
+    infringement or for any other reason (not limited to patent issues),
+    conditions are imposed on you (whether by court order, agreement or
+    otherwise) that contradict the conditions of this License, they do not
+    excuse you from the conditions of this License. If you cannot
+    distribute so as to satisfy simultaneously your obligations under this
+    License and any other pertinent obligations, then as a consequence you
+    may not distribute the Library at all. For example, if a patent license
+    would not permit royalty-free redistribution of the Library by all
+    those who receive copies directly or indirectly through you, then the
+    only way you could satisfy both it and this License would be to refrain
+    entirely from distribution of the Library.
+
+    If any portion of this section is held invalid or unenforceable under
+    any particular circumstance, the balance of the section is intended to
+    apply, and the section as a whole is intended to apply in other
+    circumstances.
+
+    It is not the purpose of this section to induce you to infringe any
+    patents or other property right claims or to contest validity of any
+    such claims; this section has the sole purpose of protecting the
+    integrity of the free software distribution system which is implemented
+    by public license practices. Many people have made generous
+    contributions to the wide range of software distributed through that
+    system in reliance on consistent application of that system; it is up
+    to the author/donor to decide if he or she is willing to distribute
+    software through any other system and a licensee cannot impose that
+    choice.
+
+    This section is intended to make thoroughly clear what is believed to
+    be a consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in certain
+    countries either by patents or by copyrighted interfaces, the original
+    copyright holder who places the Library under this License may add an
+    explicit geographical distribution limitation excluding those
+    countries, so that distribution is permitted only in or among countries
+    not thus excluded. In such case, this License incorporates the
+    limitation as if written in the body of this License.
+
+13. The Free Software Foundation may publish revised and/or new versions of
+    the Lesser General Public License from time to time. Such new versions
+    will be similar in spirit to the present version, but may differ in
+    detail to address new problems or concerns.
+
+    Each version is given a distinguishing version number. If the Library
+    specifies a version number of this License which applies to it and "any
+    later version", you have the option of following the terms and
+    conditions either of that version or of any later version published by
+    the Free Software Foundation. If the Library does not specify a license
+    version number, you may choose any version ever published by the Free
+    Software Foundation.
+
+14. If you wish to incorporate parts of the Library into other free
+    programs whose distribution conditions are incompatible with these,
+    write to the author to ask for permission. For software which is
+    copyrighted by the Free Software Foundation, write to the Free Software
+    Foundation; we sometimes make exceptions for this. Our decision will be
+    guided by the two goals of preserving the free status of all
+    derivatives of our free software and of promoting the sharing and reuse
+    of software generally.
+
+NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+    FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+    PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH
+    YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+    NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+    REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY
+    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+    THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR
+    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Libraries
+
+If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+one line to give the library's name and an idea of what it does.
+Copyright (C) year name of author
+
+This library is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at
+your option) any later version.
+
+This library is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add
+information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in
+the library `Frob' (a library for tweaking knobs) written
+by James Random Hacker.
+
+signature of Ty Coon, 1 April 1990
+Ty Coon, President of Vice
+That's all there is to it!
diff --git a/LICENSES/MIT b/LICENSES/MIT
new file mode 100644
index 0000000000..f33a68ceb3
--- /dev/null
+++ b/LICENSES/MIT
@@ -0,0 +1,30 @@
+Valid-License-Identifier: MIT
+SPDX-URL: https://spdx.org/licenses/MIT.html
+Usage-Guide:
+  To use the MIT License put the following SPDX tag/value pair into a
+  comment according to the placement guidelines in the licensing rules
+  documentation:
+    SPDX-License-Identifier: MIT
+License-Text:
+
+MIT License
+
+Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Sat Nov 12 23:22:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Sat, 12 Nov 2022 23:22:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.442899.697311 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otzpF-00066q-Cy; Sat, 12 Nov 2022 23:22:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 442899.697311; Sat, 12 Nov 2022 23:22:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otzpF-00066i-9r; Sat, 12 Nov 2022 23:22:13 +0000
Received: by outflank-mailman (input) for mailman id 442899;
 Sat, 12 Nov 2022 23:22:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzpE-00066Y-AT
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzpE-0003BM-9g
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzpE-0006Zr-8U
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=giGI17valJAyWIIkQ4F2ScznphkIgUE5Lq26FlNP7oc=; b=KOfq4TtnNi0JqJ1k4ppg3pNjxj
	qQdmpg2aqIvElYM7qy0mCW4s41PHzTrpn/h2QBiBCryZ77p/4GwMHIIlsmEXHXi7nRboi6dy0GXDw
	izJ2hkJxmC013nYR+oKdm8cyo65VzBf2YCFAyQgfG67S3QqIu+fKxucgKkulLDxq6/5c=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] Remove extra copies of licenses and license headers
Message-Id: <E1otzpE-0006Zr-8U@xenbits.xenproject.org>
Date: Sat, 12 Nov 2022 23:22:12 +0000

commit 7b068ac89024308862c4f448dd248645d2b8e882
Author:     Stefano Stabellini <stefano.stabellini@amd.com>
AuthorDate: Wed Oct 12 17:56:46 2022 -0700
Commit:     Stefano Stabellini <stefano.stabellini@amd.com>
CommitDate: Fri Nov 11 12:19:15 2022 -0800

    Remove extra copies of licenses and license headers
    
    Remove the extra copy of the GPL license and license copyright headers
    from CONTRIBUTING and the top-level COPYING.
    
    Mention of the LICENSES/ directory and also mention the SPDX tag.
    
    SPDX support is still in progress and COPYING files in subdirectories
    still need to be updated.
    
    Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 CONTRIBUTING | 151 +++----------------------
 COPYING      | 351 +----------------------------------------------------------
 2 files changed, 22 insertions(+), 480 deletions(-)

diff --git a/CONTRIBUTING b/CONTRIBUTING
index 6ec146baf0..5710a8a764 100644
--- a/CONTRIBUTING
+++ b/CONTRIBUTING
@@ -19,9 +19,7 @@ Most notably:
  - tools/xl           : LGPL v2.1
  - xen/include/public : MIT license
 
-The COMMON COPYRIGHT NOTICES section of this document contains
-sample copyright notices for the most common licenses used within
-this repository.
+See LICENSES/ for a list of licenses and SPDX tags currently used.
 
 When creating new components, new files, or importing code please follow
 the conventions outlined below. As a general rule, whenever code using a
@@ -35,17 +33,26 @@ New components
 When creating new components and directories that contain a
 significant amount of files that are licensed under licenses other
 than GPLv2 or the license specified in the COPYING file, please
-create a new COPYING file in that directory containing a copy of the
-license text and a rationale for using a different license. This helps
-ensure that the license of this new component/directory is maintained
-consistently with the original intention.
+create a new COPYING file in that directory containing the SPDX tag
+and a rationale for using a different license. This helps ensure that
+the license of this new component/directory is maintained consistently
+with the original intention.
 
 New files
 ---------
 
-If specific files that differ from the license in a directory are introduced,
-exceptions should be highlighted and discussed in the commit message or cover
-letter introducing the file.
+New files should start with a single-line SPDX comment to express the
+license. For instance, if the file is GPLv2, the comment would look
+like:
+
+/* SPDX-License-Identifier... */
+
+The recommended license of a directory will depend on the COPYING file.
+If the new file is using a different license, this should be highlighted
+and discussed in the commit message or cover letter introducing the
+file.
+
+See LICENSES/ for a list of licenses and SPDX tags currently used.
 
 Importing code
 --------------
@@ -105,127 +112,3 @@ For more information on contributing to this repository, see
  - https://wiki.xenproject.org/wiki/Category:Developers
 
 
-COMMON COPYRIGHT NOTICES
-========================
-
-The following section contains sample copyright notice for the most
-common licenses used within the Xen Project that is consistent with the
-projects coding standards.
-
-GPL v2 License
---------------
-
-/*
- * <File name>
- *
- * <One line description of the file and what it does>
- *
- * Copyright (C) <year>  <name of author and/or company>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms and conditions of the GNU General Public
- * License, version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-LGPL v2.1 License
------------------
-
-/*
- * <File name>
- *
- * <One line description of the file and what it does>
- *
- * Copyright (C) <year>  <name of author and/or company>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License, version 2.1, as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; If not, see <http://www.gnu.org/licenses/>.
- */
-
-BSD-Modified License (also known as BSD-3-Clause)
--------------------------------------------------
-
-/*
- * <File name>
- *
- * <One line description of the file and what it does>
- *
- * Copyright (C) <year>  <name of author and/or company>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials provided
- *      with the distribution.
- *   3. Neither the name of the copyright holder nor the names of its
- *      contributors may be used to endorse or promote products derived
- *      from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-MIT License
------------
-
-/*
- * <File name>
- *
- * <One line description of the file and what it does>
- *
- * Copyright (C) <year>  <name of author and/or company>
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
diff --git a/COPYING b/COPYING
index a4bc2b2dd4..824c3aa353 100644
--- a/COPYING
+++ b/COPYING
@@ -3,11 +3,11 @@ GNU General Public License
 --------------------------
 
 Most files in this repository are licensed under the terms of the GNU
-General Public License (GPL), a copy of which is attached at the end
-of this notice. Note that the only valid version of the GPL as far as
-the files in this repository are concerned is _this_ particular
-version of the license (i.e., *only* v2, not v2.2 or v3.x or
-whatever), unless explicitly otherwise stated.
+General Public License (GPL), a copy of which is present under the
+LICENSES/ directory. Note that the only valid version of the GPL as far
+as the files in this repository are concerned is _this_ particular
+version of the license (i.e., *only* v2, not v2.2 or v3.x or whatever),
+unless explicitly otherwise stated.
 
 Some code fragments in the hypervisor and associated subsystems
 include other license stanzas: the most common ones are listed in
@@ -73,344 +73,3 @@ governs the license of its containing directory and its subdirectories.
 
 For more information, see the CONTRIBUTING file.
 
-=====================================================================
-
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; If not, see <http://www.gnu.org/licenses/>.
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Sat Nov 12 23:22:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Sat, 12 Nov 2022 23:22:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.442900.697315 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otzpP-00068z-Ej; Sat, 12 Nov 2022 23:22:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 442900.697315; Sat, 12 Nov 2022 23:22:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1otzpP-00068s-BW; Sat, 12 Nov 2022 23:22:23 +0000
Received: by outflank-mailman (input) for mailman id 442900;
 Sat, 12 Nov 2022 23:22:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzpO-00068k-DN
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzpO-0003Bi-CZ
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1otzpO-0006aJ-Bm
 for xen-changelog@lists.xenproject.org; Sat, 12 Nov 2022 23:22:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=kPLc+RVFxVb7YA3wJDxk+WlgvytfcAtX1MsNqWYD2GI=; b=caDiUt40RDUfL3l2Tn9lQQ+1Oj
	1M0ZdiJ5xjVUoo2NKFyywimMKCQP2lOaxuSo8soFOEIweZha+6nLh9LwlLr9evj5vSWkWseY8UTEd
	L7wqTvEJydso7boUGHBnHl584cJ+v66WoxMs5X/5CZNO3qaNqCtKnKhwQPyqHPZBdM2k=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] Add SPDX to CODING_STYLE
Message-Id: <E1otzpO-0006aJ-Bm@xenbits.xenproject.org>
Date: Sat, 12 Nov 2022 23:22:22 +0000

commit 17dfc79ce9fd6cf508ee84a7d0d972d6abe268c2
Author:     Stefano Stabellini <stefano.stabellini@amd.com>
AuthorDate: Wed Oct 12 17:56:47 2022 -0700
Commit:     Stefano Stabellini <stefano.stabellini@amd.com>
CommitDate: Fri Nov 11 12:19:18 2022 -0800

    Add SPDX to CODING_STYLE
    
    Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 CODING_STYLE | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/CODING_STYLE b/CODING_STYLE
index 3386ee1d90..5faf274b3a 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -14,6 +14,16 @@ explicitly (e.g. tools/libxl/CODING_STYLE) but often implicitly (Linux
 coding style is fairly common). In general you should copy the style
 of the surrounding code. If you are unsure please ask.
 
+SPDX
+----
+
+New files should start with a single-line SPDX comment to express the
+license, e.g.:
+
+/* SPDX-License-Identifier: GPL-2.0 */
+
+See LICENSES/ for a list of licenses and SPDX tags currently used.
+
 MISRA C
 -------
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Mon Nov 14 22:22:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Mon, 14 Nov 2022 22:22:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.443600.698236 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ouhq6-0002QN-Kd; Mon, 14 Nov 2022 22:22:02 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 443600.698236; Mon, 14 Nov 2022 22:22:02 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ouhq6-0002QF-Hg; Mon, 14 Nov 2022 22:22:02 +0000
Received: by outflank-mailman (input) for mailman id 443600;
 Mon, 14 Nov 2022 22:22:01 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ouhq5-0002Q9-Jd
 for xen-changelog@lists.xenproject.org; Mon, 14 Nov 2022 22:22:01 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ouhq5-0001fF-J1
 for xen-changelog@lists.xenproject.org; Mon, 14 Nov 2022 22:22:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ouhq5-0001oV-Hw
 for xen-changelog@lists.xenproject.org; Mon, 14 Nov 2022 22:22:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=T+tn2og3H6X5+kmWDGbxM8lpA8GB0NWryWwE/rYkX5o=; b=58J1bpoEB8nptrCwlwaqO8skVC
	vHnRYrYJRtpya+hwdwfqJY0bWfbkKe83WDVrTkmf5yc1ge41/vET55QcZOSQwAC/9Jk2Ppehf8UM7
	0/8bqkiEVFzfI4zxKVllI9MTpECGyPGD5IAxE907HUM76jFiq8Fgiroy65/lYjmCz3oI=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] CHANGELOG: update link for RELEASE-4.16.0
Message-Id: <E1ouhq5-0001oV-Hw@xenbits.xenproject.org>
Date: Mon, 14 Nov 2022 22:22:01 +0000

commit 0d39a6d1ae3df67e11548dedfc8e1923a9002fcd
Author:     Henry Wang <Henry.Wang@arm.com>
AuthorDate: Mon Nov 14 12:01:47 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Nov 14 12:01:47 2022 +0100

    CHANGELOG: update link for RELEASE-4.16.0
    
    Signed-off-by: Henry Wang <Henry.Wang@arm.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 731db3590e..3d9f54d0f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,7 @@ Notable changes to Xen will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 
-## [4.16.0](https://xenbits.xen.org/gitweb/?p=xen.git;a=shortlog;h=staging) - 2021-12-02
+## [4.16.0](https://xenbits.xen.org/gitweb/?p=xen.git;a=shortlog;h=RELEASE-4.16.0) - 2021-12-02
 
 ### Removed
  - XENSTORED_ROOTDIR environment variable from configuartion files and
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Tue Nov 15 03:11:07 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 15 Nov 2022 03:11:07 +0000
Received: from list by lists.xenproject.org with outflank-mailman.443713.698461 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oumLm-0002TF-67; Tue, 15 Nov 2022 03:11:02 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 443713.698461; Tue, 15 Nov 2022 03:11:02 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oumLm-0002T7-32; Tue, 15 Nov 2022 03:11:02 +0000
Received: by outflank-mailman (input) for mailman id 443713;
 Tue, 15 Nov 2022 03:11:01 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oumLl-0002Sz-Iy
 for xen-changelog@lists.xenproject.org; Tue, 15 Nov 2022 03:11:01 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oumLl-0007He-I2
 for xen-changelog@lists.xenproject.org; Tue, 15 Nov 2022 03:11:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oumLl-0004Ck-H1
 for xen-changelog@lists.xenproject.org; Tue, 15 Nov 2022 03:11:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=mISzWxBCID0+X0yZS5nLPG5Yv41ouPyyVne/f0Adhmk=; b=I8HFT4mTj8mFGKDfs3TO5dJAgB
	psSoJXstjXQgbDXw9OVe+MOybibOI5gImGNiTluQEv2Vtdhf63K5AM6iyMwF9fTmhKbG4P7sSk4J8
	+IkXTs3czsduu1D9Pep80btYXoz5lbMmj6kSayJzDYQ68bKArJynlzDBjUQStWL/TXa8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] CHANGELOG: update link for RELEASE-4.16.0
Message-Id: <E1oumLl-0004Ck-H1@xenbits.xenproject.org>
Date: Tue, 15 Nov 2022 03:11:01 +0000

commit c805ceb0b26a643c7e47f01f2dbc50555d93cce8
Author:     Henry Wang <Henry.Wang@arm.com>
AuthorDate: Mon Nov 14 11:58:17 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Nov 14 11:58:17 2022 +0100

    CHANGELOG: update link for RELEASE-4.16.0
    
    Signed-off-by: Henry Wang <Henry.Wang@arm.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Acked-by: Christian Lindig <christian.lindig@citrix.com>
---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e4bae5f35..adbbb216fa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,7 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 ### Removed / support downgraded
  - dropped support for the (x86-only) "vesa-mtrr" and "vesa-remap" command line options
 
-## [4.16.0](https://xenbits.xen.org/gitweb/?p=xen.git;a=shortlog;h=staging) - 2021-12-02
+## [4.16.0](https://xenbits.xen.org/gitweb/?p=xen.git;a=shortlog;h=RELEASE-4.16.0) - 2021-12-02
 
 ### Removed
  - XENSTORED_ROOTDIR environment variable from configuartion files and
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Tue Nov 15 20:44:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Tue, 15 Nov 2022 20:44:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444065.698868 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ov2mp-0008CS-2j; Tue, 15 Nov 2022 20:44:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444065.698868; Tue, 15 Nov 2022 20:44:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ov2mo-0008CK-W6; Tue, 15 Nov 2022 20:44:02 +0000
Received: by outflank-mailman (input) for mailman id 444065;
 Tue, 15 Nov 2022 20:44:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ov2mo-0008CE-6E
 for xen-changelog@lists.xenproject.org; Tue, 15 Nov 2022 20:44:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ov2mo-0006vO-5Q
 for xen-changelog@lists.xenproject.org; Tue, 15 Nov 2022 20:44:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ov2mo-0000Q0-2a
 for xen-changelog@lists.xenproject.org; Tue, 15 Nov 2022 20:44:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=j01qdLA2rjrTbohZSstrUTC0JzLqApSFFOl2YD2Vy1E=; b=13ml2NTpLYnlbzVgnnJc9iZ8kx
	SLqYKdaLQq+dy/cqoQqAi01fYX+2CnCAm7tUnPkSU1O135JgwWbEwEoDNpEPbR5S8hayV+A6rcZYJ
	8OlcljaXXRzPZZBDO4yKyFdrcVoNXjDzlmDlPsKhuyY+BQiRSpQ+X1CplkB2sA8q7Y+U=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.15] update Xen version to 4.15.4
Message-Id: <E1ov2mo-0000Q0-2a@xenbits.xenproject.org>
Date: Tue, 15 Nov 2022 20:44:02 +0000

commit a056387c532ce6e36a0fec60788d5a5b68f978be
Author:     Jan Beulich <jbeulich@suse.com>
AuthorDate: Tue Nov 15 09:03:34 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Tue Nov 15 09:03:34 2022 +0100

    update Xen version to 4.15.4
---
 Config.mk    | 6 +++---
 xen/Makefile | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Config.mk b/Config.mk
index 9f87608f66..9696e1a151 100644
--- a/Config.mk
+++ b/Config.mk
@@ -244,15 +244,15 @@ SEABIOS_UPSTREAM_URL ?= git://xenbits.xen.org/seabios.git
 MINIOS_UPSTREAM_URL ?= git://xenbits.xen.org/mini-os.git
 endif
 OVMF_UPSTREAM_REVISION ?= a3741780fe3535e19e02efa869a7cac481891129
-QEMU_UPSTREAM_REVISION ?= qemu-xen-4.15.3
-MINIOS_UPSTREAM_REVISION ?= xen-RELEASE-4.15.3
+QEMU_UPSTREAM_REVISION ?= qemu-xen-4.15.4
+MINIOS_UPSTREAM_REVISION ?= xen-RELEASE-4.15.4
 
 SEABIOS_UPSTREAM_REVISION ?= rel-1.14.0
 
 ETHERBOOT_NICS ?= rtl8139 8086100e
 
 
-QEMU_TRADITIONAL_REVISION ?= xen-4.15.3
+QEMU_TRADITIONAL_REVISION ?= xen-4.15.4
 
 # Specify which qemu-dm to use. This may be `ioemu' to use the old
 # Mercurial in-tree version, or a local directory, or a git URL.
diff --git a/xen/Makefile b/xen/Makefile
index cd66bb3b1c..fc692c00da 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -2,7 +2,7 @@
 # All other places this is stored (eg. compile.h) should be autogenerated.
 export XEN_VERSION       = 4
 export XEN_SUBVERSION    = 15
-export XEN_EXTRAVERSION ?= .4-pre$(XEN_VENDORVERSION)
+export XEN_EXTRAVERSION ?= .4$(XEN_VENDORVERSION)
 export XEN_FULLVERSION   = $(XEN_VERSION).$(XEN_SUBVERSION)$(XEN_EXTRAVERSION)
 -include xen-version
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 03:00:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 03:00:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444484.699751 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovV8F-0003x1-Dr; Thu, 17 Nov 2022 03:00:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444484.699751; Thu, 17 Nov 2022 03:00:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovV8F-0003wL-AR; Thu, 17 Nov 2022 03:00:03 +0000
Received: by outflank-mailman (input) for mailman id 444484;
 Thu, 17 Nov 2022 03:00:01 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8D-0003eF-MT
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:01 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8D-0005FG-G0
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:01 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8D-0001LB-F4
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:01 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=X4z7QkZwmhLfXnWUHCzz5lLia43lDLZso9disn1Yngk=; b=tbDmBSCBAvctAEItblMIzdIs/i
	YNnYtTDcm9P5ZltIQ+U9Nm6OQ6wNEKeegjIHH0V/fUuNLyI0Du84WTtU/C6FFll335kktktvqHp+Z
	MrpPk/ttxNJX6kQ8PzuMUlc9ao2L4kWj4A4PUh9kVIQJHSe6do4Z6Yk9cS9xt5AJqzBo=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen/arm: vGICv3: Restore the interrupt state correctly
Message-Id: <E1ovV8D-0001LB-F4@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 03:00:01 +0000

commit aa717d803eb5442c0ab9c6f078b6ff2078092bae
Author:     Ayan Kumar Halder <ayankuma@amd.com>
AuthorDate: Thu Oct 27 20:09:13 2022 +0100
Commit:     Julien Grall <julien@xen.org>
CommitDate: Tue Nov 15 23:01:44 2022 +0000

    xen/arm: vGICv3: Restore the interrupt state correctly
    
    As "spin_lock_irqsave(&v->arch.vgic.lock, flags)" saves the current interrupt
    state in "flags", "spin_unlock_irqrestore(&v->arch.vgic.lock, flags)" should be
    used to restore the saved interrupt state.
    
    Fixes: fe7fa1332dabd9ce4 ("ARM: vGICv3: handle virtual LPI pending and property tables")
    Signed-off-by: Ayan Kumar Halder <ayankuma@amd.com>
    Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
    Reviewed-by: Andre Przywara <andre.przywara@arm.com>
    Acked-by: Julien Grall <jgrall@amazon.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/arch/arm/vgic-v3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index c19691ece0..84dc442fc6 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -582,7 +582,7 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
             write_atomic(&v->arch.vgic.rdist_pendbase, reg);
         }
 
-        spin_unlock_irqrestore(&v->arch.vgic.lock, false);
+        spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
 
         return 1;
     }
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 03:00:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 03:00:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444485.699756 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovV8P-0004RW-F1; Thu, 17 Nov 2022 03:00:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444485.699756; Thu, 17 Nov 2022 03:00:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovV8P-0004RP-C4; Thu, 17 Nov 2022 03:00:13 +0000
Received: by outflank-mailman (input) for mailman id 444485;
 Thu, 17 Nov 2022 03:00:11 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8N-0004Pt-KM
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:11 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8N-0005Hg-JT
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:11 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8N-0001Mk-IY
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:11 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=V7zx8kCKbBe222RiaK/2efyD0snOQGS2ldSxUqa29KE=; b=KEjyDswG40EJdxpoVZttzpHQDj
	UXPeRitD9yYQY08W8SSabhxs6bYDBWLyLUEJfzbyEfxv2ed+cTKz9zsdcuqdNWD4g9hl+pE1/WDgp
	Uxm4to09vsxrICoqQ7VxwlazwCJpqITMLou6EbhjfVadnREHpuDO6ze9/AffDEILzDC4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] amd/virt_ssbd: set SSBD at vCPU context switch
Message-Id: <E1ovV8N-0001Mk-IY@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 03:00:11 +0000

commit b2030e6730a2b727dbfa7ecc5b9f1deb5f50d3fb
Author:     Roger Pau Monne <roger.pau@citrix.com>
AuthorDate: Tue Nov 15 14:26:55 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 00:18:42 2022 +0000

    amd/virt_ssbd: set SSBD at vCPU context switch
    
    This fixes an issue with running C code in a GIF=0 region, that's
    problematic when using UBSAN or other instrumentation techniques.
    
    The current logic for AMD SSBD context switches it on every
    vm{entry,exit} if the Xen and guest selections don't match.  This is
    expensive when not using SPEC_CTRL, and hence should be avoided as
    much as possible.
    
    When SSBD is not being set from SPEC_CTRL on AMD don't context switch
    at vm{entry,exit} and instead only context switch SSBD when switching
    vCPUs.  This has the side effect of running Xen code with the guest
    selection of SSBD, the documentation is updated to note this behavior.
    Also note that then when `ssbd` is selected on the command line guest
    SSBD selection will not have an effect, and the hypervisor will run
    with SSBD unconditionally enabled when not using SPEC_CTRL itself.
    
    As a result of no longer running the code to set SSBD in a GIF=0
    region the locking of amd_set_legacy_ssbd() can be done using normal
    spinlocks, and some more checks can be added to assure it works as
    intended.
    
    Finally it's also worth noticing that since the guest SSBD selection
    is no longer set on vmentry the VIRT_SPEC_MSR handling needs to
    propagate the value to the hardware as part of handling the wrmsr.
    
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    
    Extend the msrs->virt_spec_ctrl context switching comment.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
 docs/misc/xen-command-line.pandoc | 10 ++++---
 xen/arch/x86/cpu/amd.c            | 55 +++++++++++++++++++++------------------
 xen/arch/x86/hvm/svm/entry.S      |  6 -----
 xen/arch/x86/hvm/svm/svm.c        | 45 ++++++++++++--------------------
 xen/arch/x86/include/asm/msr.h    | 12 +++++++--
 xen/arch/x86/msr.c                |  9 +++++++
 6 files changed, 72 insertions(+), 65 deletions(-)

diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc
index 0fbdcb574f..424b12cfb2 100644
--- a/docs/misc/xen-command-line.pandoc
+++ b/docs/misc/xen-command-line.pandoc
@@ -2372,10 +2372,12 @@ By default, Xen will use STIBP when IBRS is in use (IBRS implies STIBP), and
 when hardware hints recommend using it as a blanket setting.
 
 On hardware supporting SSBD (Speculative Store Bypass Disable), the `ssbd=`
-option can be used to force or prevent Xen using the feature itself.  On AMD
-hardware, this is a global option applied at boot, and not virtualised for
-guest use.  On Intel hardware, the feature is virtualised for guests,
-independently of Xen's choice of setting.
+option can be used to force or prevent Xen using the feature itself.  The
+feature is virtualised for guests, independently of Xen's choice of setting.
+On AMD hardware, disabling Xen SSBD usage on the command line (`ssbd=0` which
+is the default value) can lead to Xen running with the guest SSBD selection
+depending on hardware support, on the same hardware setting `ssbd=1` will
+result in SSBD always being enabled, regardless of guest choice.
 
 On hardware supporting PSFD (Predictive Store Forwarding Disable), the `psfd=`
 option can be used to force or prevent Xen using the feature itself.  By
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index 98c52d0686..a332087604 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -742,7 +742,7 @@ void amd_init_ssbd(const struct cpuinfo_x86 *c)
 }
 
 static struct ssbd_ls_cfg {
-    bool locked;
+    spinlock_t lock;
     unsigned int count;
 } __cacheline_aligned *ssbd_ls_cfg;
 static unsigned int __ro_after_init ssbd_max_cores;
@@ -753,7 +753,7 @@ bool __init amd_setup_legacy_ssbd(void)
 	unsigned int i;
 
 	if ((boot_cpu_data.x86 != 0x17 && boot_cpu_data.x86 != 0x18) ||
-	    boot_cpu_data.x86_num_siblings <= 1)
+	    boot_cpu_data.x86_num_siblings <= 1 || opt_ssbd)
 		return true;
 
 	/*
@@ -776,46 +776,51 @@ bool __init amd_setup_legacy_ssbd(void)
 	if (!ssbd_ls_cfg)
 		return false;
 
-	if (opt_ssbd)
-		for (i = 0; i < ssbd_max_cores * AMD_FAM17H_MAX_SOCKETS; i++)
-			/* Set initial state, applies to any (hotplug) CPU. */
-			ssbd_ls_cfg[i].count = boot_cpu_data.x86_num_siblings;
+	for (i = 0; i < ssbd_max_cores * AMD_FAM17H_MAX_SOCKETS; i++)
+		spin_lock_init(&ssbd_ls_cfg[i].lock);
 
 	return true;
 }
 
-/*
- * Executed from GIF==0 context: avoid using BUG/ASSERT or other functionality
- * that relies on exceptions as those are not expected to run in GIF==0
- * context.
- */
-void amd_set_legacy_ssbd(bool enable)
+static void core_set_legacy_ssbd(bool enable)
 {
 	const struct cpuinfo_x86 *c = &current_cpu_data;
 	struct ssbd_ls_cfg *status;
+	unsigned long flags;
 
 	if ((c->x86 != 0x17 && c->x86 != 0x18) || c->x86_num_siblings <= 1) {
-		set_legacy_ssbd(c, enable);
+		BUG_ON(!set_legacy_ssbd(c, enable));
 		return;
 	}
 
+	BUG_ON(c->phys_proc_id >= AMD_FAM17H_MAX_SOCKETS);
+	BUG_ON(c->cpu_core_id >= ssbd_max_cores);
 	status = &ssbd_ls_cfg[c->phys_proc_id * ssbd_max_cores +
 	                      c->cpu_core_id];
 
-	/*
-	 * Open code a very simple spinlock: this function is used with GIF==0
-	 * and different IF values, so would trigger the checklock detector.
-	 * Instead of trying to workaround the detector, use a very simple lock
-	 * implementation: it's better to reduce the amount of code executed
-	 * with GIF==0.
-	 */
-	while (test_and_set_bool(status->locked))
-		cpu_relax();
+	spin_lock_irqsave(&status->lock, flags);
 	status->count += enable ? 1 : -1;
+	ASSERT(status->count <= c->x86_num_siblings);
 	if (enable ? status->count == 1 : !status->count)
-		set_legacy_ssbd(c, enable);
-	barrier();
-	write_atomic(&status->locked, false);
+		BUG_ON(!set_legacy_ssbd(c, enable));
+	spin_unlock_irqrestore(&status->lock, flags);
+}
+
+void amd_set_legacy_ssbd(bool enable)
+{
+	if (opt_ssbd)
+		/*
+		 * Ignore attempts to turn off SSBD, it's hardcoded on the
+		 * command line.
+		 */
+		return;
+
+	if (cpu_has_virt_ssbd)
+		wrmsr(MSR_VIRT_SPEC_CTRL, enable ? SPEC_CTRL_SSBD : 0, 0);
+	else if (amd_legacy_ssbd)
+		core_set_legacy_ssbd(enable);
+	else
+		ASSERT_UNREACHABLE();
 }
 
 /*
diff --git a/xen/arch/x86/hvm/svm/entry.S b/xen/arch/x86/hvm/svm/entry.S
index a26589aa9a..981cd82e7c 100644
--- a/xen/arch/x86/hvm/svm/entry.S
+++ b/xen/arch/x86/hvm/svm/entry.S
@@ -59,9 +59,6 @@ __UNLIKELY_END(nsvm_hap)
 
         clgi
 
-        ALTERNATIVE "", STR(call vmentry_virt_spec_ctrl), \
-                        X86_FEATURE_VIRT_SC_MSR_HVM
-
         /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */
         /* SPEC_CTRL_EXIT_TO_SVM       Req: b=curr %rsp=regs/cpuinfo, Clob: acd */
         .macro svm_vmentry_spec_ctrl
@@ -131,9 +128,6 @@ __UNLIKELY_END(nsvm_hap)
         ALTERNATIVE "", svm_vmexit_spec_ctrl, X86_FEATURE_SC_MSR_HVM
         /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */
 
-        ALTERNATIVE "", STR(call vmexit_virt_spec_ctrl), \
-                        X86_FEATURE_VIRT_SC_MSR_HVM
-
         /*
          * STGI is executed unconditionally, and is sufficiently serialising
          * to safely resolve any Spectre-v1 concerns in the above logic.
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 1aeaabcb13..fa73257203 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -973,6 +973,16 @@ static void cf_check svm_ctxt_switch_from(struct vcpu *v)
 
     /* Resume use of ISTs now that the host TR is reinstated. */
     enable_each_ist(idt_tables[cpu]);
+
+    /*
+     * Possibly clear previous guest selection of SSBD if set.  Note that
+     * SPEC_CTRL.SSBD is already handled by svm_vmexit_spec_ctrl.
+     */
+    if ( v->arch.msrs->virt_spec_ctrl.raw & SPEC_CTRL_SSBD )
+    {
+        ASSERT(v->domain->arch.cpuid->extd.virt_ssbd);
+        amd_set_legacy_ssbd(false);
+    }
 }
 
 static void cf_check svm_ctxt_switch_to(struct vcpu *v)
@@ -1000,6 +1010,13 @@ static void cf_check svm_ctxt_switch_to(struct vcpu *v)
 
     if ( cpu_has_msr_tsc_aux )
         wrmsr_tsc_aux(v->arch.msrs->tsc_aux);
+
+    /* Load SSBD if set by the guest. */
+    if ( v->arch.msrs->virt_spec_ctrl.raw & SPEC_CTRL_SSBD )
+    {
+        ASSERT(v->domain->arch.cpuid->extd.virt_ssbd);
+        amd_set_legacy_ssbd(true);
+    }
 }
 
 static void noreturn cf_check svm_do_resume(void)
@@ -3116,34 +3133,6 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
     vmcb_set_vintr(vmcb, intr);
 }
 
-/* Called with GIF=0. */
-void vmexit_virt_spec_ctrl(void)
-{
-    unsigned int val = opt_ssbd ? SPEC_CTRL_SSBD : 0;
-
-    if ( val == current->arch.msrs->virt_spec_ctrl.raw )
-        return;
-
-    if ( cpu_has_virt_ssbd )
-        wrmsr(MSR_VIRT_SPEC_CTRL, val, 0);
-    else
-        amd_set_legacy_ssbd(val);
-}
-
-/* Called with GIF=0. */
-void vmentry_virt_spec_ctrl(void)
-{
-    unsigned int val = current->arch.msrs->virt_spec_ctrl.raw;
-
-    if ( val == (opt_ssbd ? SPEC_CTRL_SSBD : 0) )
-        return;
-
-    if ( cpu_has_virt_ssbd )
-        wrmsr(MSR_VIRT_SPEC_CTRL, val, 0);
-    else
-        amd_set_legacy_ssbd(val);
-}
-
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/include/asm/msr.h b/xen/arch/x86/include/asm/msr.h
index de18e90b2e..dd1eee04a6 100644
--- a/xen/arch/x86/include/asm/msr.h
+++ b/xen/arch/x86/include/asm/msr.h
@@ -378,8 +378,16 @@ struct vcpu_msrs
     /*
      * 0xc001011f - MSR_VIRT_SPEC_CTRL (if !X86_FEATURE_AMD_SSBD)
      *
-     * AMD only. Guest selected value, context switched on guest VM
-     * entry/exit.
+     * AMD only, used on Zen1 and older hardware (pre-AMD_SSBD).  Holds the
+     * the guests value.
+     *
+     * In the default case, Xen doesn't protect itself from SSB, and guests
+     * are expected to use VIRT_SPEC_CTRL.SSBD=1 sparingly.  Xen therefore
+     * runs in the guest kernel's choice of SSBD.
+     *
+     * However, if the global enable `spec-ctrl=ssbd` is selected, hardware is
+     * always configured with SSBD=1 and the guest's setting is never loaded
+     * into hardware.
      */
     struct {
         uint32_t raw;
diff --git a/xen/arch/x86/msr.c b/xen/arch/x86/msr.c
index 95416995a5..cf46b18aa6 100644
--- a/xen/arch/x86/msr.c
+++ b/xen/arch/x86/msr.c
@@ -24,6 +24,7 @@
 #include <xen/nospec.h>
 #include <xen/sched.h>
 
+#include <asm/amd.h>
 #include <asm/debugreg.h>
 #include <asm/hvm/nestedhvm.h>
 #include <asm/hvm/viridian.h>
@@ -697,7 +698,15 @@ int guest_wrmsr(struct vcpu *v, uint32_t msr, uint64_t val)
                 msrs->spec_ctrl.raw &= ~SPEC_CTRL_SSBD;
         }
         else
+        {
             msrs->virt_spec_ctrl.raw = val & SPEC_CTRL_SSBD;
+            if ( v == curr )
+                /*
+                 * Propagate the value to hardware, as it won't be set on guest
+                 * resume path.
+                 */
+                amd_set_legacy_ssbd(val & SPEC_CTRL_SSBD);
+        }
         break;
 
     case MSR_AMD64_DE_CFG:
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 03:00:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 03:00:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444486.699760 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovV8Z-0004mV-GD; Thu, 17 Nov 2022 03:00:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444486.699760; Thu, 17 Nov 2022 03:00:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovV8Z-0004mN-Dc; Thu, 17 Nov 2022 03:00:23 +0000
Received: by outflank-mailman (input) for mailman id 444486;
 Thu, 17 Nov 2022 03:00:21 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8X-0004et-Nu
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:21 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8X-0005I0-My
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:21 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8X-0001ND-Lq
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:21 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=FDkEY7TOxRHC12d82XfEq8kTd8q1jYvJLXtKsTpV1zA=; b=jUrsW/Do9wMosSCxORmcq7fjWv
	pGqPgOcIHDcU2HvR4YrxMYXPk+YSxAyxZ+ET7iOGeQzr/I5xjq5j+fxYuU2krjAUDdtrqmlDlxV/O
	DeTj/hXKX/qEmaEX5q8hE80o3d/8KcxhugB3DkggO8iQ+TZX8QyDhKk1/hENeJ7lQagU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] amd: remove VIRT_SC_MSR_HVM synthetic feature
Message-Id: <E1ovV8X-0001ND-Lq@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 03:00:21 +0000

commit e6440e2a72776149bacf3ab72c6453f5b72dea5f
Author:     Roger Pau Monne <roger.pau@citrix.com>
AuthorDate: Tue Nov 15 14:26:56 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 00:18:42 2022 +0000

    amd: remove VIRT_SC_MSR_HVM synthetic feature
    
    With the previous bugfix, X86_FEATURE_VIRT_SC_MSR_HVM is no longer
    needed and can be replaced with an __initdata variable.  This also
    leaves asm/cpufeatures.h as it was in 4.16 which will simplify
    backports.
    
    No functional change intended.
    
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
    
    Rewrite commit message.  Move amd_virt_spec_ctrl into __initdata.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
 xen/arch/x86/cpu/amd.c                 | 1 +
 xen/arch/x86/cpuid.c                   | 9 +++++----
 xen/arch/x86/include/asm/amd.h         | 1 +
 xen/arch/x86/include/asm/cpufeatures.h | 2 +-
 xen/arch/x86/spec_ctrl.c               | 7 +++----
 5 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index a332087604..070060d90b 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -49,6 +49,7 @@ boolean_param("allow_unsafe", opt_allow_unsafe);
 /* Signal whether the ACPI C1E quirk is required. */
 bool __read_mostly amd_acpi_c1e_quirk;
 bool __ro_after_init amd_legacy_ssbd;
+bool __initdata amd_virt_spec_ctrl;
 
 static inline int rdmsr_amd_safe(unsigned int msr, unsigned int *lo,
 				 unsigned int *hi)
diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c
index 822f9ace10..acc2f606ce 100644
--- a/xen/arch/x86/cpuid.c
+++ b/xen/arch/x86/cpuid.c
@@ -3,6 +3,7 @@
 #include <xen/param.h>
 #include <xen/sched.h>
 #include <xen/nospec.h>
+#include <asm/amd.h>
 #include <asm/cpuid.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/nestedhvm.h>
@@ -543,9 +544,9 @@ static void __init calculate_hvm_max_policy(void)
 
     /*
      * VIRT_SSBD is exposed in the default policy as a result of
-     * VIRT_SC_MSR_HVM being set, it also needs exposing in the max policy.
+     * amd_virt_spec_ctrl being set, it also needs exposing in the max policy.
      */
-    if ( boot_cpu_has(X86_FEATURE_VIRT_SC_MSR_HVM) )
+    if ( amd_virt_spec_ctrl )
         __set_bit(X86_FEATURE_VIRT_SSBD, hvm_featureset);
 
     /*
@@ -606,9 +607,9 @@ static void __init calculate_hvm_def_policy(void)
 
     /*
      * Only expose VIRT_SSBD if AMD_SSBD is not available, and thus
-     * VIRT_SC_MSR_HVM is set.
+     * amd_virt_spec_ctrl is set.
      */
-    if ( boot_cpu_has(X86_FEATURE_VIRT_SC_MSR_HVM) )
+    if ( amd_virt_spec_ctrl )
         __set_bit(X86_FEATURE_VIRT_SSBD, hvm_featureset);
 
     sanitise_featureset(hvm_featureset);
diff --git a/xen/arch/x86/include/asm/amd.h b/xen/arch/x86/include/asm/amd.h
index 6a42f68542..a975d3de26 100644
--- a/xen/arch/x86/include/asm/amd.h
+++ b/xen/arch/x86/include/asm/amd.h
@@ -152,6 +152,7 @@ extern bool amd_acpi_c1e_quirk;
 void amd_check_disable_c1e(unsigned int port, u8 value);
 
 extern bool amd_legacy_ssbd;
+extern bool amd_virt_spec_ctrl;
 bool amd_setup_legacy_ssbd(void);
 void amd_set_legacy_ssbd(bool enable);
 
diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h
index c68ced1b82..865f110986 100644
--- a/xen/arch/x86/include/asm/cpufeatures.h
+++ b/xen/arch/x86/include/asm/cpufeatures.h
@@ -24,7 +24,7 @@ XEN_CPUFEATURE(APERFMPERF,        X86_SYNTH( 8)) /* APERFMPERF */
 XEN_CPUFEATURE(MFENCE_RDTSC,      X86_SYNTH( 9)) /* MFENCE synchronizes RDTSC */
 XEN_CPUFEATURE(XEN_SMEP,          X86_SYNTH(10)) /* SMEP gets used by Xen itself */
 XEN_CPUFEATURE(XEN_SMAP,          X86_SYNTH(11)) /* SMAP gets used by Xen itself */
-XEN_CPUFEATURE(VIRT_SC_MSR_HVM,   X86_SYNTH(12)) /* MSR_VIRT_SPEC_CTRL exposed to HVM */
+/* Bit 12 unused. */
 XEN_CPUFEATURE(IND_THUNK_LFENCE,  X86_SYNTH(13)) /* Use IND_THUNK_LFENCE */
 XEN_CPUFEATURE(IND_THUNK_JMP,     X86_SYNTH(14)) /* Use IND_THUNK_JMP */
 XEN_CPUFEATURE(SC_NO_BRANCH_HARDEN, X86_SYNTH(15)) /* (Disable) Conditional branch hardening */
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index a0835143e3..a320b81947 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -515,12 +515,11 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
            (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ||
             boot_cpu_has(X86_FEATURE_SC_RSB_HVM) ||
             boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) ||
-            boot_cpu_has(X86_FEATURE_VIRT_SC_MSR_HVM) ||
+            amd_virt_spec_ctrl ||
             opt_eager_fpu || opt_md_clear_hvm)       ? ""               : " None",
            boot_cpu_has(X86_FEATURE_SC_MSR_HVM)      ? " MSR_SPEC_CTRL" : "",
            (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ||
-            boot_cpu_has(X86_FEATURE_VIRT_SC_MSR_HVM)) ? " MSR_VIRT_SPEC_CTRL"
-                                                       : "",
+            amd_virt_spec_ctrl)                      ? " MSR_VIRT_SPEC_CTRL" : "",
            boot_cpu_has(X86_FEATURE_SC_RSB_HVM)      ? " RSB"           : "",
            opt_eager_fpu                             ? " EAGER_FPU"     : "",
            opt_md_clear_hvm                          ? " MD_CLEAR"      : "",
@@ -1256,7 +1255,7 @@ void __init init_speculation_mitigations(void)
     /* Support VIRT_SPEC_CTRL.SSBD if AMD_SSBD is not available. */
     if ( opt_msr_sc_hvm && !cpu_has_amd_ssbd &&
          (cpu_has_virt_ssbd || (amd_legacy_ssbd && amd_setup_legacy_ssbd())) )
-        setup_force_cpu_cap(X86_FEATURE_VIRT_SC_MSR_HVM);
+        amd_virt_spec_ctrl = true;
 
     /* Figure out default_xen_spec_ctrl. */
     if ( has_spec_ctrl && ibrs )
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 03:00:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 03:00:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444487.699764 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovV8j-0004pM-II; Thu, 17 Nov 2022 03:00:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444487.699764; Thu, 17 Nov 2022 03:00:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovV8j-0004pE-FB; Thu, 17 Nov 2022 03:00:33 +0000
Received: by outflank-mailman (input) for mailman id 444487;
 Thu, 17 Nov 2022 03:00:31 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8h-0004p2-Qw
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:31 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8h-0005IA-Pz
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:31 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovV8h-0001Nc-Oz
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 03:00:31 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=bbqd90DRghpTkobEtZD7LMu4Ja3qhMEcMHbLYNsDLXc=; b=wPReI7luvwqlTeJPRwhQ4RfbeD
	9bGUQgVDErapZDmDAP++NrCdETkIKqj+cUVlRDgGoVFuRx9NCXpaaoMwYbz3Kqd2MgH1LkT4dzPZC
	ZMKeQEv99QUC7q9Frem32Uf5gQdvyfvbVqtWvpwbSl0H8l4yLtPZkZ0bs/dCwCKr2Pts=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] Introduce CC-BY-4.0 license under LICENSES/
Message-Id: <E1ovV8h-0001Nc-Oz@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 03:00:31 +0000

commit 2a98e98f96d1aafddf8869db5e2382d0ddaae01a
Author:     Stefano Stabellini <sstabellini@kernel.org>
AuthorDate: Mon Nov 14 14:36:04 2022 -0800
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 00:18:42 2022 +0000

    Introduce CC-BY-4.0 license under LICENSES/
    
    We use CC-BY-4.0 for many of the documents under docs/ so we should have
    a copy of the license.
    
    Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 LICENSES/CC-BY-4.0 | 409 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 409 insertions(+)

diff --git a/LICENSES/CC-BY-4.0 b/LICENSES/CC-BY-4.0
new file mode 100644
index 0000000000..27dfefa95c
--- /dev/null
+++ b/LICENSES/CC-BY-4.0
@@ -0,0 +1,409 @@
+Valid-License-Identifier: CC-BY-4.0
+SPDX-URL: https://spdx.org/licenses/CC-BY-4.0
+Usage-Guide:
+  Do NOT use this license for code, but it's acceptable for content like artwork
+  or documentation. When using it for the latter, it's best to use it together
+  with a GPL2 compatible license using "OR", as CC-BY-4.0 texts processed by
+  the kernel's build system might combine it with content taken from more
+  restrictive licenses.
+  To use the Creative Commons Attribution 4.0 International license put
+  the following SPDX tag/value pair into a comment according to the
+  placement guidelines in the licensing rules documentation:
+    SPDX-License-Identifier: CC-BY-4.0
+License-Text:
+
+Creative Commons Attribution 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+     Considerations for licensors: Our public licenses are
+     intended for use by those authorized to give the public
+     permission to use material in ways otherwise restricted by
+     copyright and certain other rights. Our licenses are
+     irrevocable. Licensors should read and understand the terms
+     and conditions of the license they choose before applying it.
+     Licensors should also secure all rights necessary before
+     applying our licenses so that the public can reuse the
+     material as expected. Licensors should clearly mark any
+     material not subject to the license. This includes other CC-
+     licensed material, or material used under an exception or
+     limitation to copyright. More considerations for licensors:
+    wiki.creativecommons.org/Considerations_for_licensors
+
+     Considerations for the public: By using one of our public
+     licenses, a licensor grants the public permission to use the
+     licensed material under specified terms and conditions. If
+     the licensor's permission is not necessary for any reason--for
+     example, because of any applicable exception or limitation to
+     copyright--then that use is not regulated by the license. Our
+     licenses grant only permissions under copyright and certain
+     other rights that a licensor has authority to grant. Use of
+     the licensed material may still be restricted for other
+     reasons, including because others have copyright or other
+     rights in the material. A licensor may make special requests,
+     such as asking that all changes be marked or described.
+     Although not required by our licenses, you are encouraged to
+     respect those requests where reasonable. More considerations
+     for the public:
+    wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution 4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution 4.0 International Public License ("Public License"). To the
+extent this Public License may be interpreted as a contract, You are
+granted the Licensed Rights in consideration of Your acceptance of
+these terms and conditions, and the Licensor grants You such rights in
+consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+  a. Adapted Material means material subject to Copyright and Similar
+     Rights that is derived from or based upon the Licensed Material
+     and in which the Licensed Material is translated, altered,
+     arranged, transformed, or otherwise modified in a manner requiring
+     permission under the Copyright and Similar Rights held by the
+     Licensor. For purposes of this Public License, where the Licensed
+     Material is a musical work, performance, or sound recording,
+     Adapted Material is always produced where the Licensed Material is
+     synched in timed relation with a moving image.
+
+  b. Adapter's License means the license You apply to Your Copyright
+     and Similar Rights in Your contributions to Adapted Material in
+     accordance with the terms and conditions of this Public License.
+
+  c. Copyright and Similar Rights means copyright and/or similar rights
+     closely related to copyright including, without limitation,
+     performance, broadcast, sound recording, and Sui Generis Database
+     Rights, without regard to how the rights are labeled or
+     categorized. For purposes of this Public License, the rights
+     specified in Section 2(b)(1)-(2) are not Copyright and Similar
+     Rights.
+
+  d. Effective Technological Measures means those measures that, in the
+     absence of proper authority, may not be circumvented under laws
+     fulfilling obligations under Article 11 of the WIPO Copyright
+     Treaty adopted on December 20, 1996, and/or similar international
+     agreements.
+
+  e. Exceptions and Limitations means fair use, fair dealing, and/or
+     any other exception or limitation to Copyright and Similar Rights
+     that applies to Your use of the Licensed Material.
+
+  f. Licensed Material means the artistic or literary work, database,
+     or other material to which the Licensor applied this Public
+     License.
+
+  g. Licensed Rights means the rights granted to You subject to the
+     terms and conditions of this Public License, which are limited to
+     all Copyright and Similar Rights that apply to Your use of the
+     Licensed Material and that the Licensor has authority to license.
+
+  h. Licensor means the individual(s) or entity(ies) granting rights
+     under this Public License.
+
+  i. Share means to provide material to the public by any means or
+     process that requires permission under the Licensed Rights, such
+     as reproduction, public display, public performance, distribution,
+     dissemination, communication, or importation, and to make material
+     available to the public including in ways that members of the
+     public may access the material from a place and at a time
+     individually chosen by them.
+
+  j. Sui Generis Database Rights means rights other than copyright
+     resulting from Directive 96/9/EC of the European Parliament and of
+     the Council of 11 March 1996 on the legal protection of databases,
+     as amended and/or succeeded, as well as other essentially
+     equivalent rights anywhere in the world.
+
+  k. You means the individual or entity exercising the Licensed Rights
+     under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+  a. License grant.
+
+       1. Subject to the terms and conditions of this Public License,
+          the Licensor hereby grants You a worldwide, royalty-free,
+          non-sublicensable, non-exclusive, irrevocable license to
+          exercise the Licensed Rights in the Licensed Material to:
+
+            a. reproduce and Share the Licensed Material, in whole or
+               in part; and
+
+            b. produce, reproduce, and Share Adapted Material.
+
+       2. Exceptions and Limitations. For the avoidance of doubt, where
+          Exceptions and Limitations apply to Your use, this Public
+          License does not apply, and You do not need to comply with
+          its terms and conditions.
+
+       3. Term. The term of this Public License is specified in Section
+          6(a).
+
+       4. Media and formats; technical modifications allowed. The
+          Licensor authorizes You to exercise the Licensed Rights in
+          all media and formats whether now known or hereafter created,
+          and to make technical modifications necessary to do so. The
+          Licensor waives and/or agrees not to assert any right or
+          authority to forbid You from making technical modifications
+          necessary to exercise the Licensed Rights, including
+          technical modifications necessary to circumvent Effective
+          Technological Measures. For purposes of this Public License,
+          simply making modifications authorized by this Section 2(a)
+          (4) never produces Adapted Material.
+
+       5. Downstream recipients.
+
+            a. Offer from the Licensor -- Licensed Material. Every
+               recipient of the Licensed Material automatically
+               receives an offer from the Licensor to exercise the
+               Licensed Rights under the terms and conditions of this
+               Public License.
+
+            b. No downstream restrictions. You may not offer or impose
+               any additional or different terms or conditions on, or
+               apply any Effective Technological Measures to, the
+               Licensed Material if doing so restricts exercise of the
+               Licensed Rights by any recipient of the Licensed
+               Material.
+
+       6. No endorsement. Nothing in this Public License constitutes or
+          may be construed as permission to assert or imply that You
+          are, or that Your use of the Licensed Material is, connected
+          with, or sponsored, endorsed, or granted official status by,
+          the Licensor or others designated to receive attribution as
+          provided in Section 3(a)(1)(A)(i).
+
+  b. Other rights.
+
+       1. Moral rights, such as the right of integrity, are not
+          licensed under this Public License, nor are publicity,
+          privacy, and/or other similar personality rights; however, to
+          the extent possible, the Licensor waives and/or agrees not to
+          assert any such rights held by the Licensor to the limited
+          extent necessary to allow You to exercise the Licensed
+          Rights, but not otherwise.
+
+       2. Patent and trademark rights are not licensed under this
+          Public License.
+
+       3. To the extent possible, the Licensor waives any right to
+          collect royalties from You for the exercise of the Licensed
+          Rights, whether directly or through a collecting society
+          under any voluntary or waivable statutory or compulsory
+          licensing scheme. In all other cases the Licensor expressly
+          reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+  a. Attribution.
+
+       1. If You Share the Licensed Material (including in modified
+          form), You must:
+
+            a. retain the following if it is supplied by the Licensor
+               with the Licensed Material:
+
+                 i. identification of the creator(s) of the Licensed
+                    Material and any others designated to receive
+                    attribution, in any reasonable manner requested by
+                    the Licensor (including by pseudonym if
+                    designated);
+
+                ii. a copyright notice;
+
+               iii. a notice that refers to this Public License;
+
+                iv. a notice that refers to the disclaimer of
+                    warranties;
+
+                 v. a URI or hyperlink to the Licensed Material to the
+                    extent reasonably practicable;
+
+            b. indicate if You modified the Licensed Material and
+               retain an indication of any previous modifications; and
+
+            c. indicate the Licensed Material is licensed under this
+               Public License, and include the text of, or the URI or
+               hyperlink to, this Public License.
+
+       2. You may satisfy the conditions in Section 3(a)(1) in any
+          reasonable manner based on the medium, means, and context in
+          which You Share the Licensed Material. For example, it may be
+          reasonable to satisfy the conditions by providing a URI or
+          hyperlink to a resource that includes the required
+          information.
+
+       3. If requested by the Licensor, You must remove any of the
+          information required by Section 3(a)(1)(A) to the extent
+          reasonably practicable.
+
+       4. If You Share Adapted Material You produce, the Adapter's
+          License You apply must not prevent recipients of the Adapted
+          Material from complying with this Public License.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+     to extract, reuse, reproduce, and Share all or a substantial
+     portion of the contents of the database;
+
+  b. if You include all or a substantial portion of the database
+     contents in a database in which You have Sui Generis Database
+     Rights, then the database in which You have Sui Generis Database
+     Rights (but not its individual contents) is Adapted Material; and
+
+  c. You must comply with the conditions in Section 3(a) if You Share
+     all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+  c. The disclaimer of warranties and limitation of liability provided
+     above shall be interpreted in a manner that, to the extent
+     possible, most closely approximates an absolute disclaimer and
+     waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+  a. This Public License applies for the term of the Copyright and
+     Similar Rights licensed here. However, if You fail to comply with
+     this Public License, then Your rights under this Public License
+     terminate automatically.
+
+  b. Where Your right to use the Licensed Material has terminated under
+     Section 6(a), it reinstates:
+
+       1. automatically as of the date the violation is cured, provided
+          it is cured within 30 days of Your discovery of the
+          violation; or
+
+       2. upon express reinstatement by the Licensor.
+
+     For the avoidance of doubt, this Section 6(b) does not affect any
+     right the Licensor may have to seek remedies for Your violations
+     of this Public License.
+
+  c. For the avoidance of doubt, the Licensor may also offer the
+     Licensed Material under separate terms or conditions or stop
+     distributing the Licensed Material at any time; however, doing so
+     will not terminate this Public License.
+
+  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+     License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+  a. The Licensor shall not be bound by any additional or different
+     terms or conditions communicated by You unless expressly agreed.
+
+  b. Any arrangements, understandings, or agreements regarding the
+     Licensed Material not stated herein are separate from and
+     independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+  a. For the avoidance of doubt, this Public License does not, and
+     shall not be interpreted to, reduce, limit, restrict, or impose
+     conditions on any use of the Licensed Material that could lawfully
+     be made without permission under this Public License.
+
+  b. To the extent possible, if any provision of this Public License is
+     deemed unenforceable, it shall be automatically reformed to the
+     minimum extent necessary to make it enforceable. If the provision
+     cannot be reformed, it shall be severed from this Public License
+     without affecting the enforceability of the remaining terms and
+     conditions.
+
+  c. No term or condition of this Public License will be waived and no
+     failure to comply consented to unless expressly agreed to by the
+     Licensor.
+
+  d. Nothing in this Public License constitutes or may be interpreted
+     as a limitation upon, or waiver of, any privileges and immunities
+     that apply to the Licensor or You, including from the legal
+     processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the "Licensor." The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 10:11:11 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 10:11:11 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444875.700001 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbrM-0001Lv-El; Thu, 17 Nov 2022 10:11:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444875.700001; Thu, 17 Nov 2022 10:11:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbrM-0001Ln-C2; Thu, 17 Nov 2022 10:11:04 +0000
Received: by outflank-mailman (input) for mailman id 444875;
 Thu, 17 Nov 2022 10:11:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbrK-0001LO-Co
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbrK-0007K5-BJ
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbrK-0002Ti-AN
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=sA4eriMmDc+shw+IbOAMjUqGy/L73Io1Iz0z/p7tO+Y=; b=bUpCzAf8CVNVQxUDedldHkpXog
	8h3XaydsV2zEZgMGKeo7J7Y/QkjP5fIkBjirfzCCu5arppCcq/HsUfqIyHvA2pY0Pc6X7O07iWjNg
	K4qP2HEHTfjf3cCE9YNEgsQcOCN6ALxhj9HhfHxJyt4wWwU2izZVO2yEX7M8LCjrIo7A=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] x86/spec-ctrl: Fill in whitepaper URL
Message-Id: <E1ovbrK-0002Ti-AN@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 10:11:02 +0000

commit 764146ed8a7a44034c3efe658333993ca250d69a
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Mon Nov 14 21:41:08 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 12:54:08 2022 +0000

    x86/spec-ctrl: Fill in whitepaper URL
    
    ... now that we a link available.
    
    Fixes: 9deaf2d932f0 ("x86/spec-ctrl: Enable Zen2 chickenbit")
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/arch/x86/cpu/amd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index 070060d90b..1ddb55cbe5 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -828,7 +828,7 @@ void amd_set_legacy_ssbd(bool enable)
  * On Zen2 we offer this chicken (bit) on the altar of Speculation.
  *
  * Refer to the AMD Branch Type Confusion whitepaper:
- * https://XXX
+ * https://www.amd.com/system/files/documents/technical-guidance-for-mitigating-branch-type-confusion.pdf
  *
  * Setting this unnamed bit supposedly causes prediction information on
  * non-branch instructions to be ignored.  It is to be set unilaterally in
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 10:11:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 10:11:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444876.700005 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbrW-0001Ne-G9; Thu, 17 Nov 2022 10:11:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444876.700005; Thu, 17 Nov 2022 10:11:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbrW-0001NW-DX; Thu, 17 Nov 2022 10:11:14 +0000
Received: by outflank-mailman (input) for mailman id 444876;
 Thu, 17 Nov 2022 10:11:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbrU-0001NG-F8
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbrU-0007Na-EM
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbrU-0002UB-DP
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=re+YDgshTuJCd96WI2m7ySnzCDVbS9ytKZHlfOskcAg=; b=Zg77OuyrSGTRZFDa5Ekbr11s9Q
	hYwilTi/dV5ZBfxTxmocBohwBg7o1QlYbjdHF6X9Bbwg5tEarhoXnxvOSUsUdisgKhBRbzgwdH/Yx
	f8p1IeYZNNgr4uqwSWrTAvZYjiTEgDddYk/cuOVrmutbONRvjcTZrkkLO/c4BlfUCzUQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen: Add licence information to public/errno.h
Message-Id: <E1ovbrU-0002UB-DP@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 10:11:12 +0000

commit 97abc04e387bb070f9c917269be0ff4e5a813bcf
Author:     Anthony PERARD <anthony.perard@citrix.com>
AuthorDate: Thu Nov 3 11:51:59 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 16:15:23 2022 +0000

    xen: Add licence information to public/errno.h
    
    Fixes: 81f559e97974 ("make error codes a formal part of the ABI")
    Reported-by: Andrew Cooper <Andrew.Cooper3@citrix.com>
    Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/include/public/errno.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/xen/include/public/errno.h b/xen/include/public/errno.h
index 5c53af6af9..6bdc8c5079 100644
--- a/xen/include/public/errno.h
+++ b/xen/include/public/errno.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: MIT */
+
 /*
  * There are two expected ways of including this header.
  *
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 10:11:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 10:11:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444880.700022 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbrf-0001gy-Qt; Thu, 17 Nov 2022 10:11:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444880.700022; Thu, 17 Nov 2022 10:11:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbrf-0001go-NY; Thu, 17 Nov 2022 10:11:23 +0000
Received: by outflank-mailman (input) for mailman id 444880;
 Thu, 17 Nov 2022 10:11:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbre-0001gF-IA
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbre-0007Nz-HL
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbre-0002Ua-GY
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=p7EIHhUhO173Qikh0PXFZ7YSbmfIZrZIyXfXE07CWvo=; b=ii0Eg78RBPloy4T00amGfzRzDr
	5YhmWGUVBa2I2x/959oyE6x0zEYvgWzrVNQ0fCdHzjOp/nW9C1gtWRCCL6MO6uXOWtSy/B8RX2Eec
	9/JsMix2YVrGdIhT0ItA0yr7WwXDBEjLVRThcp/pyS5cF54nXSfHm58ywH6T3hRpRcm8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen: Used SPDX identifier in some public headers
Message-Id: <E1ovbre-0002Ua-GY@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 10:11:22 +0000

commit 224dab941629f9cfb793999bcece4c31776b7827
Author:     Anthony PERARD <anthony.perard@citrix.com>
AuthorDate: Thu Nov 3 11:52:00 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 16:15:23 2022 +0000

    xen: Used SPDX identifier in some public headers
    
    The script "tools/include/xen-foreign/mkheader.py" is going to do a
    sanity check on the licences of these headers. To ease this, we will
    replace the verbatim copy of the MIT licence by its SPDX identifier
    equivalent.
    
    The text of the licence has been check to be the same as the one at
    https://spdx.org/licenses/MIT.html, except we don't have "(including
    the next paragraph)". The text is also the same as the one in
    "xen/include/public/COPYING".
    
    Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/include/public/arch-arm.h            | 19 +------------------
 xen/include/public/arch-x86/xen-x86_32.h | 19 +------------------
 xen/include/public/arch-x86/xen-x86_64.h | 19 +------------------
 xen/include/public/arch-x86/xen.h        | 19 +------------------
 xen/include/public/xen.h                 | 19 +------------------
 5 files changed, 5 insertions(+), 90 deletions(-)

diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index c8b6058d3a..1528ced509 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * arch-arm.h
  *
  * Guest OS interface to ARM Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright 2011 (C) Citrix Systems
  */
 
diff --git a/xen/include/public/arch-x86/xen-x86_32.h b/xen/include/public/arch-x86/xen-x86_32.h
index 19d7388633..139438e835 100644
--- a/xen/include/public/arch-x86/xen-x86_32.h
+++ b/xen/include/public/arch-x86/xen-x86_32.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * xen-x86_32.h
  *
  * Guest OS interface to x86 32-bit Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2004-2007, K A Fraser
  */
 
diff --git a/xen/include/public/arch-x86/xen-x86_64.h b/xen/include/public/arch-x86/xen-x86_64.h
index 40aed14366..5d9035ed22 100644
--- a/xen/include/public/arch-x86/xen-x86_64.h
+++ b/xen/include/public/arch-x86/xen-x86_64.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * xen-x86_64.h
  *
  * Guest OS interface to x86 64-bit Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2004-2006, K A Fraser
  */
 
diff --git a/xen/include/public/arch-x86/xen.h b/xen/include/public/arch-x86/xen.h
index 546dd4496a..93b9d600b0 100644
--- a/xen/include/public/arch-x86/xen.h
+++ b/xen/include/public/arch-x86/xen.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * arch-x86/xen.h
  *
  * Guest OS interface to x86 Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2004-2006, K A Fraser
  */
 
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index e373592c33..920567e006 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * xen.h
  *
  * Guest OS interface to Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2004, K A Fraser
  */
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 10:11:33 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 10:11:33 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444881.700025 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbrp-0001n0-SQ; Thu, 17 Nov 2022 10:11:33 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444881.700025; Thu, 17 Nov 2022 10:11:33 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbrp-0001mo-PQ; Thu, 17 Nov 2022 10:11:33 +0000
Received: by outflank-mailman (input) for mailman id 444881;
 Thu, 17 Nov 2022 10:11:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbro-0001mP-Ly
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbro-0007O9-LB
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbro-0002VB-JU
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=bIxnuK/W4SOtfULS0qaUoJqJ+6VeMTqs6h8hlL6aqcc=; b=rBe0Vm1BGUD9WwLCNgufQGdTUc
	Wh8ru/7mgNBUfkP023KyEm49Ng6tDf2IJPZZVg8smvV8jrugHbwh2B9Vk7rusha8l1XcK9KVR9Rgl
	yhjS96vcqjo4ehWa+go/G1HA5Ka1BCgqPng8OCpS/LWN3/Ld+Y9mHGQYHs2Cc7VEwv70=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/include/xen-foreign: Add SPDX identifier to generated headers
Message-Id: <E1ovbro-0002VB-JU@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 10:11:32 +0000

commit c62748312e0adec0cbcf0f8d7d126080e5e43a82
Author:     Anthony PERARD <anthony.perard@citrix.com>
AuthorDate: Thu Nov 3 11:52:01 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 16:15:23 2022 +0000

    tools/include/xen-foreign: Add SPDX identifier to generated headers
    
    The headers install in "/usr/include/xen/foreign/" are missing a
    licence header. This patch adds a SPDX identifier to clarify that
    the MIT licence is used.
    
    The script now check that the licence of the input file is also MIT,
    by checking for the presence of the SPDX identifier.
    
    Also add information about which files are used to generate the
    headers.
    
    Reported-by: Andrew Cooper <Andrew.Cooper3@citrix.com>
    Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/include/xen-foreign/mkheader.py | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/tools/include/xen-foreign/mkheader.py b/tools/include/xen-foreign/mkheader.py
index fb268f0dce..081b57f842 100644
--- a/tools/include/xen-foreign/mkheader.py
+++ b/tools/include/xen-foreign/mkheader.py
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import print_function
+
 import sys, re;
 from structs import unions, structs, defines;
 
@@ -114,23 +116,39 @@ input  = "";
 output = "";
 fileid = re.sub("[-.]", "_", "__FOREIGN_%s__" % outfile.upper());
 
-# read input header files
 for name in infiles:
     f = open(name, "r");
+
+    # Sanity check the licence of the input file(s)
+    line = f.readline()
+    if line != "/* SPDX-License-Identifier: MIT */\n":
+        print("Error: %s %s Missing or unexpected SPDX tag '%s'" %
+              (sys.argv[0], name, line.strip()), file=sys.stderr)
+        exit(1)
+
     input += f.read();
     f.close();
 
+# replace path in "infiles" by path in '/usr/include' to avoid exposing the
+# build directory path in the generated headers.
+headers_name_list = ""
+public_headers_location = 'xen/include/public/'
+for name in infiles:
+    i = name.rindex(public_headers_location)
+    i += len(public_headers_location)
+    headers_name_list += " xen/%s" % (name[i:])
+
 # add header
-output += """
+output += """/* SPDX-License-Identifier: MIT */
 /*
  * public xen defines and struct for %s
- * generated by %s -- DO NOT EDIT
+ * generated from%s by %s -- DO NOT EDIT
  */
 
 #ifndef %s
 #define %s 1
 
-""" % (arch, sys.argv[0], fileid, fileid)
+""" % (arch, headers_name_list, sys.argv[0], fileid, fileid)
 
 if arch in header:
     output += header[arch];
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 10:11:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 10:11:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444883.700029 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbs0-0001w6-U1; Thu, 17 Nov 2022 10:11:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444883.700029; Thu, 17 Nov 2022 10:11:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbs0-0001vz-R3; Thu, 17 Nov 2022 10:11:44 +0000
Received: by outflank-mailman (input) for mailman id 444883;
 Thu, 17 Nov 2022 10:11:42 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbry-0001vU-Ou
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbry-0007Oe-O9
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbry-0002W8-NF
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=B4sUPTUOXYVehJLG2dH8jvLpHLfX2SXzdDnJp5zH1do=; b=l+OjPaDVSq6WJLywCZ1JJEZsTr
	tbV0EK+LfTX+YG72TJy0yGQC8NZf7YMrlDXMTMC5GKvfdbFDmv2i6z9yhZZ+TqY/CJrz2gkSq+d2J
	yW8VnclMNVKo3jvxbXMOWKhZN8vnP3Jii6CeKx8JeLcxhp8bZvGnPa7J0tQ3cHrCxD/4=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen: Add licence header to device_tree_defs.h
Message-Id: <E1ovbry-0002W8-NF@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 10:11:42 +0000

commit 8e75d6c36b0bb70e80d8e570d578706f7d51765a
Author:     Anthony PERARD <anthony.perard@citrix.com>
AuthorDate: Thu Nov 3 11:52:02 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 16:15:23 2022 +0000

    xen: Add licence header to device_tree_defs.h
    
    This header have been created by moving code from other part of the
    project and miss a licence header. The original source code was some
    version of GPL or LGPL but we intend to have the public header to be
    MIT so they can be included easily in other projects.
    
    Part of device_tree_defs.h were moved from libxl_arm.c which is
    LGPL-2.1-only. And part were moved from device_tree.h that is
    GPL-2.0-only.
    
    Part of the original code were added by Julien Grall @ Linaro in
    commits c3ba52a84dd8 and 405c167f0ec9 and 886f34045bf0. The other part
    were added by Ian Campbell @ Citrix, with commit 0c64527e7fc9.
    
    Resolves: xen-project/xen#35
    Fixes: 1c898a9fec7e ("xen/arm: move a few DT related defines to public/device_tree_defs.h")
    Reported-by: Andrew Cooper <Andrew.Cooper3@citrix.com>
    Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com> [Citrix relicensing]
    Acked-by: Grant Likely <grant.likely@linaro.org> [Linaro relicensing]
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/include/public/device_tree_defs.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/xen/include/public/device_tree_defs.h b/xen/include/public/device_tree_defs.h
index 228daafe81..9e80d0499d 100644
--- a/xen/include/public/device_tree_defs.h
+++ b/xen/include/public/device_tree_defs.h
@@ -1,3 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (c) 2013 Linaro Limited
+ * Copyright (c) 2015 Citrix Systems, Inc
+ */
+
 #ifndef __XEN_DEVICE_TREE_DEFS_H__
 #define __XEN_DEVICE_TREE_DEFS_H__
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 10:11:54 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 10:11:54 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444886.700043 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbsA-0002Jz-Db; Thu, 17 Nov 2022 10:11:54 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444886.700043; Thu, 17 Nov 2022 10:11:54 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbsA-0002Jr-A1; Thu, 17 Nov 2022 10:11:54 +0000
Received: by outflank-mailman (input) for mailman id 444886;
 Thu, 17 Nov 2022 10:11:52 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbs8-0002Iq-Rj
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:52 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbs8-0007P4-R5
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:52 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbs8-0002Wh-QB
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:11:52 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=Omnaej+4Lv6ZxR/nHT/ix7k3ZgIdIDmv5kB4tQqlGDo=; b=gGSU7L5rA05mgBCepScFh9LTrK
	YSjpcBUvA6jD8GKQoymy9E+fY3s7PPHjo/E7lpehSGQY+MsxLmxW7+PyQzW77s/c3B8C52HESkClu
	Y/+Jorz/rJVVqCc8QX9gWJSHDrp3hkh22im6Ev/e+TFfcVt9pMLlz2G1af531v2IVa6E=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] Rework COPYING installed in /usr/include/xen/, due to several licences
Message-Id: <E1ovbs8-0002Wh-QB@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 10:11:52 +0000

commit 4ea75e9a9058db43a495f646132734b51d438ec1
Author:     Anthony PERARD <anthony.perard@citrix.com>
AuthorDate: Thu Nov 3 11:52:03 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 16:15:23 2022 +0000

    Rework COPYING installed in /usr/include/xen/, due to several licences
    
    The notice in the COPYING file in "xen/include/public/COPYING" doesn't
    really apply to the files that ultimately are been install at
    "/usr/include/xen". The issue are headers in the "sys/" subdirectory
    that comes from other projects such as Linux or FreeBSD.
    
    The main issue is that there are two headers that have a different
    licence than the MIT licence:
    
    - xen-sys/Linux/gntalloc.h (installed as "sys/gntalloc.h") is public
      domain.
    - xen-sys/FreeBSD/gntdev.h (installed as "sys/gntdev.h") is BSD-2.
    
    To clarify this, we'll install a COPYING file with a different notice.
    
    Reported-by: Andrew Cooper <Andrew.Cooper3@citrix.com>
    Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 .gitignore                   |  1 -
 tools/include/Makefile       |  1 -
 tools/include/xen/.gitignore |  2 ++
 tools/include/xen/COPYING    | 26 ++++++++++++++++++++++++++
 4 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
index 418bdfaebf..ea3243af9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -194,7 +194,6 @@ tools/hotplug/NetBSD/rc.d/xencommons
 tools/hotplug/NetBSD/rc.d/xendriverdomain
 tools/include/acpi
 tools/include/_libxl*.h
-tools/include/xen/*
 tools/include/xen-xsm/*
 tools/include/xen-foreign/*.(c|h|size)
 tools/include/xen-foreign/checker
diff --git a/tools/include/Makefile b/tools/include/Makefile
index 81c3d09039..f838171e8c 100644
--- a/tools/include/Makefile
+++ b/tools/include/Makefile
@@ -24,7 +24,6 @@ xen-foreign:
 xen-dir:
 	mkdir -p xen/libelf acpi
 	find xen/ acpi/ -type l -exec rm '{}' +
-	ln -s $(XEN_ROOT)/xen/include/public/COPYING xen/
 	ln -s $(XEN_ROOT)/xen/include/public/*.h xen/
 	ln -s $(XEN_ROOT)/xen/include/public/*/ xen/
 	ln -s ../xen-sys/$(XEN_OS) xen/sys
diff --git a/tools/include/xen/.gitignore b/tools/include/xen/.gitignore
new file mode 100644
index 0000000000..0628b2daf1
--- /dev/null
+++ b/tools/include/xen/.gitignore
@@ -0,0 +1,2 @@
+*
+!COPYING
diff --git a/tools/include/xen/COPYING b/tools/include/xen/COPYING
new file mode 100644
index 0000000000..fe3f9b7557
--- /dev/null
+++ b/tools/include/xen/COPYING
@@ -0,0 +1,26 @@
+XEN NOTICE
+==========
+
+This licence applies to all files within this subdirectory ("/usr/include/xen")
+with the exception of "sys/" which may include headers under different
+licences.
+
+=====================================================================
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Thu Nov 17 10:12:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2022 10:12:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.444890.700048 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbsK-0002Zh-IY; Thu, 17 Nov 2022 10:12:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 444890.700048; Thu, 17 Nov 2022 10:12:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ovbsK-0002Za-Eu; Thu, 17 Nov 2022 10:12:04 +0000
Received: by outflank-mailman (input) for mailman id 444890;
 Thu, 17 Nov 2022 10:12:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbsJ-0002Yx-0B
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:12:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbsI-0007PR-VY
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:12:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ovbsI-0002XH-Ud
 for xen-changelog@lists.xenproject.org; Thu, 17 Nov 2022 10:12:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=xY8t96dX4qCAI4c0WH0QxDQ2lzuRB/yRiZGSuXBZ5VQ=; b=2dtwDGNm3rMXSXLM04vtymLsxo
	SZ6lRBzc8NfcUCMQJSRrjk4tbX7f6CBile4P0+xoT1fD+mpKW5mpyKhmGSacUlf92fnQt585PXEuV
	mKwPXPomkv+eAJJnrtS3Tj84fLTKiaCMQ80WGNKlPZx+edd14OXMP+Ep/DTG80kDTrew=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen: Used SPDX identifier in public headers
Message-Id: <E1ovbsI-0002XH-Ud@xenbits.xenproject.org>
Date: Thu, 17 Nov 2022 10:12:02 +0000

commit f5d56f4b253072264efc0fece698a91779e362f5
Author:     Anthony PERARD <anthony.perard@citrix.com>
AuthorDate: Thu Nov 3 11:52:04 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Wed Nov 16 16:15:23 2022 +0000

    xen: Used SPDX identifier in public headers
    
    The text of the licence has been check to be the same as the one at
    https://spdx.org/licenses/MIT.html, except we don't have "(including
    the next paragraph)".
    
    Mecanical change done with a script.
    
    Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/include/public/arch-arm/hvm/save.h       | 19 +------------------
 xen/include/public/arch-arm/smccc.h          | 19 +------------------
 xen/include/public/arch-x86/cpufeatureset.h  | 19 +------------------
 xen/include/public/arch-x86/cpuid.h          | 19 +------------------
 xen/include/public/arch-x86/guest-acpi.h     | 19 +------------------
 xen/include/public/arch-x86/hvm/save.h       | 19 +------------------
 xen/include/public/arch-x86/hvm/start_info.h | 19 +------------------
 xen/include/public/arch-x86/pmu.h            | 19 +------------------
 xen/include/public/arch-x86/xen-mca.h        | 19 +------------------
 xen/include/public/arch-x86_32.h             | 19 +------------------
 xen/include/public/arch-x86_64.h             | 19 +------------------
 xen/include/public/argo.h                    | 19 +------------------
 xen/include/public/callback.h                | 19 +------------------
 xen/include/public/dom0_ops.h                | 19 +------------------
 xen/include/public/domctl.h                  | 19 +------------------
 xen/include/public/elfnote.h                 | 19 +------------------
 xen/include/public/event_channel.h           | 19 +------------------
 xen/include/public/features.h                | 19 +------------------
 xen/include/public/grant_table.h             | 19 +------------------
 xen/include/public/hvm/dm_op.h               | 19 +------------------
 xen/include/public/hvm/e820.h                | 19 +------------------
 xen/include/public/hvm/hvm_info_table.h      | 19 +------------------
 xen/include/public/hvm/hvm_op.h              | 19 +------------------
 xen/include/public/hvm/hvm_vcpu.h            | 19 +------------------
 xen/include/public/hvm/hvm_xs_strings.h      | 19 +------------------
 xen/include/public/hvm/ioreq.h               | 19 +------------------
 xen/include/public/hvm/params.h              | 19 +------------------
 xen/include/public/hvm/pvdrivers.h           | 19 +------------------
 xen/include/public/hvm/save.h                | 19 +------------------
 xen/include/public/hypfs.h                   | 19 +------------------
 xen/include/public/io/9pfs.h                 | 19 +------------------
 xen/include/public/io/blkif.h                | 19 +------------------
 xen/include/public/io/cameraif.h             | 19 +------------------
 xen/include/public/io/console.h              | 19 +------------------
 xen/include/public/io/displif.h              | 19 +------------------
 xen/include/public/io/fbif.h                 | 19 +------------------
 xen/include/public/io/fsif.h                 | 19 +------------------
 xen/include/public/io/kbdif.h                | 19 +------------------
 xen/include/public/io/libxenvchan.h          | 19 +------------------
 xen/include/public/io/netif.h                | 19 +------------------
 xen/include/public/io/pciif.h                | 19 +------------------
 xen/include/public/io/protocols.h            | 19 +------------------
 xen/include/public/io/pvcalls.h              | 19 +------------------
 xen/include/public/io/ring.h                 | 19 +------------------
 xen/include/public/io/sndif.h                | 19 +------------------
 xen/include/public/io/tpmif.h                | 19 +------------------
 xen/include/public/io/usbif.h                | 19 +------------------
 xen/include/public/io/vscsiif.h              | 19 +------------------
 xen/include/public/io/xenbus.h               | 19 +------------------
 xen/include/public/io/xs_wire.h              | 19 +------------------
 xen/include/public/kexec.h                   | 19 +------------------
 xen/include/public/memory.h                  | 19 +------------------
 xen/include/public/nmi.h                     | 19 +------------------
 xen/include/public/physdev.h                 | 19 +------------------
 xen/include/public/platform.h                | 19 +------------------
 xen/include/public/pmu.h                     | 19 +------------------
 xen/include/public/sched.h                   | 19 +------------------
 xen/include/public/sysctl.h                  | 19 +------------------
 xen/include/public/tmem.h                    | 19 +------------------
 xen/include/public/trace.h                   | 19 +------------------
 xen/include/public/vcpu.h                    | 19 +------------------
 xen/include/public/version.h                 | 19 +------------------
 xen/include/public/vm_event.h                | 19 +------------------
 xen/include/public/xen-compat.h              | 19 +------------------
 xen/include/public/xencomm.h                 | 19 +------------------
 xen/include/public/xenoprof.h                | 19 +------------------
 xen/include/public/xsm/flask_op.h            | 19 +------------------
 67 files changed, 67 insertions(+), 1206 deletions(-)

diff --git a/xen/include/public/arch-arm/hvm/save.h b/xen/include/public/arch-arm/hvm/save.h
index 75b8e65bcb..fc1b28f59b 100644
--- a/xen/include/public/arch-arm/hvm/save.h
+++ b/xen/include/public/arch-arm/hvm/save.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * Structure definitions for HVM state that is held by Xen and must
  * be saved along with the domain's memory and device-model state.
  *
  * Copyright (c) 2012 Citrix Systems Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef __XEN_PUBLIC_HVM_SAVE_ARM_H__
diff --git a/xen/include/public/arch-arm/smccc.h b/xen/include/public/arch-arm/smccc.h
index 17dc6d8829..802d800aad 100644
--- a/xen/include/public/arch-arm/smccc.h
+++ b/xen/include/public/arch-arm/smccc.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * smccc.h
  *
  * SMC/HVC interface in accordance with SMC Calling Convention.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright 2017 (C) EPAM Systems
  */
 
diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h
index 02675e9c75..7915f5826f 100644
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * arch-x86/cpufeatureset.h
  *
  * CPU featureset definitions
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2015, 2016 Citrix Systems, Inc.
  */
 
diff --git a/xen/include/public/arch-x86/cpuid.h b/xen/include/public/arch-x86/cpuid.h
index c49eefeaf8..7ecd16ae05 100644
--- a/xen/include/public/arch-x86/cpuid.h
+++ b/xen/include/public/arch-x86/cpuid.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * arch-x86/cpuid.h
  *
  * CPUID interface to Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2007 Citrix Systems, Inc.
  *
  * Authors:
diff --git a/xen/include/public/arch-x86/guest-acpi.h b/xen/include/public/arch-x86/guest-acpi.h
index 3d79a31fd8..de40259b6a 100644
--- a/xen/include/public/arch-x86/guest-acpi.h
+++ b/xen/include/public/arch-x86/guest-acpi.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * arch-x86/guest-acpi.h
  *
  * Guest ACPI interface to x86 Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  */
 
 #ifndef __XEN_PUBLIC_ARCH_X86_GUEST_ACPI_H__
diff --git a/xen/include/public/arch-x86/hvm/save.h b/xen/include/public/arch-x86/hvm/save.h
index 773a380bc2..7ecacadde1 100644
--- a/xen/include/public/arch-x86/hvm/save.h
+++ b/xen/include/public/arch-x86/hvm/save.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * Structure definitions for HVM state that is held by Xen and must
  * be saved along with the domain's memory and device-model state.
  *
  * Copyright (c) 2007 XenSource Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef __XEN_PUBLIC_HVM_SAVE_X86_H__
diff --git a/xen/include/public/arch-x86/hvm/start_info.h b/xen/include/public/arch-x86/hvm/start_info.h
index 50af9ea2ff..e33557c0b4 100644
--- a/xen/include/public/arch-x86/hvm/start_info.h
+++ b/xen/include/public/arch-x86/hvm/start_info.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2016, Citrix Systems, Inc.
  */
 
diff --git a/xen/include/public/arch-x86/pmu.h b/xen/include/public/arch-x86/pmu.h
index 464c65dac1..d0a99268af 100644
--- a/xen/include/public/arch-x86/pmu.h
+++ b/xen/include/public/arch-x86/pmu.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
  */
 
diff --git a/xen/include/public/arch-x86/xen-mca.h b/xen/include/public/arch-x86/xen-mca.h
index d930c344c0..b897536ec5 100644
--- a/xen/include/public/arch-x86/xen-mca.h
+++ b/xen/include/public/arch-x86/xen-mca.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * arch-x86/mca.h
  *
@@ -5,24 +6,6 @@
  * Author: Christoph Egger <Christoph.Egger@amd.com>
  *
  * Guest OS machine check interface to x86 Xen.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 /* Full MCA functionality has the following Usecases from the guest side:
diff --git a/xen/include/public/arch-x86_32.h b/xen/include/public/arch-x86_32.h
index dfabdcc345..c0cf8c7bcd 100644
--- a/xen/include/public/arch-x86_32.h
+++ b/xen/include/public/arch-x86_32.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * arch-x86_32.h
  *
  * Guest OS interface to x86 32-bit Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2004-2006, K A Fraser
  */
 
diff --git a/xen/include/public/arch-x86_64.h b/xen/include/public/arch-x86_64.h
index c40b3f9651..5db52de695 100644
--- a/xen/include/public/arch-x86_64.h
+++ b/xen/include/public/arch-x86_64.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * arch-x86_64.h
  *
  * Guest OS interface to x86 64-bit Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2004-2006, K A Fraser
  */
 
diff --git a/xen/include/public/argo.h b/xen/include/public/argo.h
index 3397a3a33f..84a4cb118b 100644
--- a/xen/include/public/argo.h
+++ b/xen/include/public/argo.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * Argo : Hypervisor-Mediated data eXchange
  *
@@ -6,24 +7,6 @@
  * Copyright (c) 2010, Citrix Systems
  * Copyright (c) 2018-2019, BAE Systems
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  */
 
 #ifndef __XEN_PUBLIC_ARGO_H__
diff --git a/xen/include/public/callback.h b/xen/include/public/callback.h
index 8f937880e2..7f13be66f3 100644
--- a/xen/include/public/callback.h
+++ b/xen/include/public/callback.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * callback.h
  *
  * Register guest OS callbacks with Xen.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2006, Ian Campbell
  */
 
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index 76598dda18..9fba71d3a8 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * dom0_ops.h
  *
  * Process command requests from domain-0 guest OS.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2002-2003, B Dragovic
  * Copyright (c) 2002-2006, K Fraser
  */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index b2ae839c36..966bf4323c 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * domctl.h
  *
  * Domain management operations. For use by node control stack.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2002-2003, B Dragovic
  * Copyright (c) 2002-2006, K Fraser
  */
diff --git a/xen/include/public/elfnote.h b/xen/include/public/elfnote.h
index 181cbc4ec7..8bf54d035b 100644
--- a/xen/include/public/elfnote.h
+++ b/xen/include/public/elfnote.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * elfnote.h
  *
  * Definitions used for the Xen ELF notes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2006, Ian Campbell, XenSource Ltd.
  */
 
diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h
index 73c9f38ce1..0d91a1c4af 100644
--- a/xen/include/public/event_channel.h
+++ b/xen/include/public/event_channel.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * event_channel.h
  *
  * Event channels between domains.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2003-2004, K A Fraser.
  */
 
diff --git a/xen/include/public/features.h b/xen/include/public/features.h
index 9ee2f760ef..d2a9175aae 100644
--- a/xen/include/public/features.h
+++ b/xen/include/public/features.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * features.h
  *
  * Feature flags, reported by XENVER_get_features.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2006, Keir Fraser <keir@xensource.com>
  */
 
diff --git a/xen/include/public/grant_table.h b/xen/include/public/grant_table.h
index 7934d7b718..1dfa17a6d0 100644
--- a/xen/include/public/grant_table.h
+++ b/xen/include/public/grant_table.h
@@ -1,27 +1,10 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * grant_table.h
  *
  * Interface for granting foreign access to page frames, and receiving
  * page-ownership transfers.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2004, K A Fraser
  */
 
diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h
index fa3f083fed..acdf91693d 100644
--- a/xen/include/public/hvm/dm_op.h
+++ b/xen/include/public/hvm/dm_op.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * Copyright (c) 2016, Citrix Systems Inc
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  */
 
 #ifndef __XEN_PUBLIC_HVM_DM_OP_H__
diff --git a/xen/include/public/hvm/e820.h b/xen/include/public/hvm/e820.h
index 4c42f3341e..5879b8ff7b 100644
--- a/xen/include/public/hvm/e820.h
+++ b/xen/include/public/hvm/e820.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2006, Keir Fraser
  */
 
diff --git a/xen/include/public/hvm/hvm_info_table.h b/xen/include/public/hvm/hvm_info_table.h
index c46e03ef17..a885f356db 100644
--- a/xen/include/public/hvm/hvm_info_table.h
+++ b/xen/include/public/hvm/hvm_info_table.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * hvm/hvm_info_table.h
  *
  * HVM parameter and information table, written into guest memory map.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2006, Keir Fraser
  */
 
diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h
index 870ec52060..e22adf0319 100644
--- a/xen/include/public/hvm/hvm_op.h
+++ b/xen/include/public/hvm/hvm_op.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2007, Keir Fraser
  */
 
diff --git a/xen/include/public/hvm/hvm_vcpu.h b/xen/include/public/hvm/hvm_vcpu.h
index 661cf89e1e..4a43401144 100644
--- a/xen/include/public/hvm/hvm_vcpu.h
+++ b/xen/include/public/hvm/hvm_vcpu.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2015, Roger Pau Monne <roger.pau@citrix.com>
  */
 
diff --git a/xen/include/public/hvm/hvm_xs_strings.h b/xen/include/public/hvm/hvm_xs_strings.h
index fba2546424..e1ed078628 100644
--- a/xen/include/public/hvm/hvm_xs_strings.h
+++ b/xen/include/public/hvm/hvm_xs_strings.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * hvm/hvm_xs_strings.h
  *
  * HVM xenstore strings used in HVMLOADER.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2013, Citrix Systems
  */
 
diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h
index c511fae8e7..7a6bc760d0 100644
--- a/xen/include/public/hvm/ioreq.h
+++ b/xen/include/public/hvm/ioreq.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * ioreq.h: I/O request definitions for device models
  * Copyright (c) 2004, Intel Corporation.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef _IOREQ_H_
diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
index c9d6e70d7b..a22b4ed45d 100644
--- a/xen/include/public/hvm/params.h
+++ b/xen/include/public/hvm/params.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2007, Keir Fraser
  */
 
diff --git a/xen/include/public/hvm/pvdrivers.h b/xen/include/public/hvm/pvdrivers.h
index 3241f94eb9..62252db626 100644
--- a/xen/include/public/hvm/pvdrivers.h
+++ b/xen/include/public/hvm/pvdrivers.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * pvdrivers.h: Register of PV drivers product numbers.
  * Copyright (c) 2012, Citrix Systems Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef _XEN_PUBLIC_PVDRIVERS_H_
diff --git a/xen/include/public/hvm/save.h b/xen/include/public/hvm/save.h
index bea5e9f50f..464ebdb0da 100644
--- a/xen/include/public/hvm/save.h
+++ b/xen/include/public/hvm/save.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * hvm/save.h
  *
@@ -5,24 +6,6 @@
  * be saved along with the domain's memory and device-model state.
  *
  * Copyright (c) 2007 XenSource Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef __XEN_PUBLIC_HVM_SAVE_H__
diff --git a/xen/include/public/hypfs.h b/xen/include/public/hypfs.h
index 2b7a66d68d..70047e1762 100644
--- a/xen/include/public/hypfs.h
+++ b/xen/include/public/hypfs.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * Xen Hypervisor Filesystem
  *
  * Copyright (c) 2019, SUSE Software Solutions Germany GmbH
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  */
 
 #ifndef __XEN_PUBLIC_HYPFS_H__
diff --git a/xen/include/public/io/9pfs.h b/xen/include/public/io/9pfs.h
index 4bfd5d48b1..ad26bd69eb 100644
--- a/xen/include/public/io/9pfs.h
+++ b/xen/include/public/io/9pfs.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * 9pfs.h -- Xen 9PFS transport
  *
  * Refer to docs/misc/9pfs.markdown for the specification
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2017 Stefano Stabellini <stefano@aporeto.com>
  */
 
diff --git a/xen/include/public/io/blkif.h b/xen/include/public/io/blkif.h
index ab863f175a..22f1eef0c0 100644
--- a/xen/include/public/io/blkif.h
+++ b/xen/include/public/io/blkif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * blkif.h
  *
  * Unified block-device I/O interface for Xen guest OSes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2003-2004, Keir Fraser
  * Copyright (c) 2012, Spectra Logic Corporation
  */
diff --git a/xen/include/public/io/cameraif.h b/xen/include/public/io/cameraif.h
index acbcbf3bd4..13763abef9 100644
--- a/xen/include/public/io/cameraif.h
+++ b/xen/include/public/io/cameraif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * cameraif.h
  *
  * Unified camera device I/O interface for Xen guest OSes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2018-2019 EPAM Systems Inc.
  *
  * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
diff --git a/xen/include/public/io/console.h b/xen/include/public/io/console.h
index 4811f47220..4509b4b689 100644
--- a/xen/include/public/io/console.h
+++ b/xen/include/public/io/console.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * console.h
  *
  * Console I/O interface for Xen guest OSes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2005, Keir Fraser
  */
 
diff --git a/xen/include/public/io/displif.h b/xen/include/public/io/displif.h
index 0055895510..73d0cbdf15 100644
--- a/xen/include/public/io/displif.h
+++ b/xen/include/public/io/displif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * displif.h
  *
  * Unified display device I/O interface for Xen guest OSes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2016-2017 EPAM Systems Inc.
  *
  * Authors: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
diff --git a/xen/include/public/io/fbif.h b/xen/include/public/io/fbif.h
index cc25aab32e..93c73195d8 100644
--- a/xen/include/public/io/fbif.h
+++ b/xen/include/public/io/fbif.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * fbif.h -- Xen virtual frame buffer device
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
  * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
  */
diff --git a/xen/include/public/io/fsif.h b/xen/include/public/io/fsif.h
index a8bea193b5..ec57850233 100644
--- a/xen/include/public/io/fsif.h
+++ b/xen/include/public/io/fsif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * fsif.h
  *
  * Interface to FS level split device drivers.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2007, Grzegorz Milos, <gm281@cam.ac.uk>.
  */
 
diff --git a/xen/include/public/io/kbdif.h b/xen/include/public/io/kbdif.h
index a6b01c52c7..4bde6b3821 100644
--- a/xen/include/public/io/kbdif.h
+++ b/xen/include/public/io/kbdif.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * kbdif.h -- Xen virtual keyboard/mouse
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
  * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
  */
diff --git a/xen/include/public/io/libxenvchan.h b/xen/include/public/io/libxenvchan.h
index 44284f437a..2eab65cb19 100644
--- a/xen/include/public/io/libxenvchan.h
+++ b/xen/include/public/io/libxenvchan.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
 /**
  * @file
  * @section AUTHORS
@@ -10,24 +11,6 @@
  *
  * @section LICENSE
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * @section DESCRIPTION
  *
  *  Originally borrowed from the Qubes OS Project, http://www.qubes-os.org,
diff --git a/xen/include/public/io/netif.h b/xen/include/public/io/netif.h
index 3509b096f8..c13b85061d 100644
--- a/xen/include/public/io/netif.h
+++ b/xen/include/public/io/netif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * netif.h
  *
  * Unified network-device I/O interface for Xen guest OSes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2003-2004, Keir Fraser
  */
 
diff --git a/xen/include/public/io/pciif.h b/xen/include/public/io/pciif.h
index a4ba13cc13..dbe825ecc3 100644
--- a/xen/include/public/io/pciif.h
+++ b/xen/include/public/io/pciif.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * PCI Backend/Frontend Common Data Structures & Macros
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
  */
 #ifndef __XEN_PCI_COMMON_H__
diff --git a/xen/include/public/io/protocols.h b/xen/include/public/io/protocols.h
index 52b4de0f81..7815e1ff0f 100644
--- a/xen/include/public/io/protocols.h
+++ b/xen/include/public/io/protocols.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * protocols.h
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2008, Keir Fraser
  */
 
diff --git a/xen/include/public/io/pvcalls.h b/xen/include/public/io/pvcalls.h
index 6da6b5533a..230b0719e3 100644
--- a/xen/include/public/io/pvcalls.h
+++ b/xen/include/public/io/pvcalls.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * pvcalls.h -- Xen PV Calls Protocol
  *
@@ -6,24 +7,6 @@
  * The header is provided as a C reference for the specification. In
  * case of conflict, the specification is authoritative.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2017 Stefano Stabellini <stefano@aporeto.com>
  */
 
diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h
index ab3439bd58..025939278b 100644
--- a/xen/include/public/io/ring.h
+++ b/xen/include/public/io/ring.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * ring.h
  *
  * Shared producer-consumer ring macros.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Tim Deegan and Andrew Warfield November 2004.
  */
 
diff --git a/xen/include/public/io/sndif.h b/xen/include/public/io/sndif.h
index 402033cf49..4234a47c87 100644
--- a/xen/include/public/io/sndif.h
+++ b/xen/include/public/io/sndif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * sndif.h
  *
  * Unified sound-device I/O interface for Xen guest OSes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2013-2015 GlobalLogic Inc.
  * Copyright (C) 2016-2017 EPAM Systems Inc.
  *
diff --git a/xen/include/public/io/tpmif.h b/xen/include/public/io/tpmif.h
index 9743dc9369..ad02dbaf1a 100644
--- a/xen/include/public/io/tpmif.h
+++ b/xen/include/public/io/tpmif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * tpmif.h
  *
  * TPM I/O interface for Xen guest OSes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2005, IBM Corporation
  *
  * Author: Stefan Berger, stefanb@us.ibm.com
diff --git a/xen/include/public/io/usbif.h b/xen/include/public/io/usbif.h
index c0a552e195..875af0dc7c 100644
--- a/xen/include/public/io/usbif.h
+++ b/xen/include/public/io/usbif.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * usbif.h
  *
@@ -5,24 +6,6 @@
  *
  * Copyright (C) 2009, FUJITSU LABORATORIES LTD.
  * Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef __XEN_PUBLIC_IO_USBIF_H__
diff --git a/xen/include/public/io/vscsiif.h b/xen/include/public/io/vscsiif.h
index 8553b17cc6..f5fc7de725 100644
--- a/xen/include/public/io/vscsiif.h
+++ b/xen/include/public/io/vscsiif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * vscsiif.h
  *
  * Based on the blkif.h code.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright(c) FUJITSU Limited 2008.
  */
 
diff --git a/xen/include/public/io/xenbus.h b/xen/include/public/io/xenbus.h
index 927f9db552..9cd0cd7c67 100644
--- a/xen/include/public/io/xenbus.h
+++ b/xen/include/public/io/xenbus.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /*****************************************************************************
  * xenbus.h
  *
  * Xenbus protocol details.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2005 XenSource Ltd.
  */
 
diff --git a/xen/include/public/io/xs_wire.h b/xen/include/public/io/xs_wire.h
index 05d3069e63..04e6849feb 100644
--- a/xen/include/public/io/xs_wire.h
+++ b/xen/include/public/io/xs_wire.h
@@ -1,25 +1,8 @@
+/* SPDX-License-Identifier: MIT */
 /*
  * Details of the "wire" protocol between Xen Store Daemon and client
  * library or guest kernel.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2005 Rusty Russell IBM Corporation
  */
 
diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h
index 3cb961fdab..40d79e936b 100644
--- a/xen/include/public/kexec.h
+++ b/xen/include/public/kexec.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * kexec.h - Public portion
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Xen port written by:
  * - Simon 'Horms' Horman <horms@verge.net.au>
  * - Magnus Damm <magnus@valinux.co.jp>
diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h
index f8d26fb77d..29cf5c8239 100644
--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * memory.h
  *
  * Memory reservation and information.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
  */
 
diff --git a/xen/include/public/nmi.h b/xen/include/public/nmi.h
index 4dd7294d72..5900703f5f 100644
--- a/xen/include/public/nmi.h
+++ b/xen/include/public/nmi.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * nmi.h
  *
  * NMI callback registration and reason codes.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
  */
 
diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h
index f8d1905e30..f0c0d4727c 100644
--- a/xen/include/public/physdev.h
+++ b/xen/include/public/physdev.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2006, Keir Fraser
  */
 
diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h
index 8100133509..5e1494fe9a 100644
--- a/xen/include/public/platform.h
+++ b/xen/include/public/platform.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * platform.h
  *
  * Hardware platform operations. Intended for use by domain-0 kernel.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2002-2006, K Fraser
  */
 
diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
index cc2fcf8816..eb87a81e7b 100644
--- a/xen/include/public/pmu.h
+++ b/xen/include/public/pmu.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
  */
 
diff --git a/xen/include/public/sched.h b/xen/include/public/sched.h
index 811bd87c82..b4362c6a1d 100644
--- a/xen/include/public/sched.h
+++ b/xen/include/public/sched.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * sched.h
  *
  * Scheduler state interactions
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
  */
 
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index 5672906729..051bff39b3 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * sysctl.h
  *
  * System management operations. For use by node control stack.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2002-2006, K Fraser
  */
 
diff --git a/xen/include/public/tmem.h b/xen/include/public/tmem.h
index 362ba45d5a..da68de76fe 100644
--- a/xen/include/public/tmem.h
+++ b/xen/include/public/tmem.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * tmem.h
  *
  * Guest OS interface to Xen Transcendent Memory.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2004, K A Fraser
  */
 
diff --git a/xen/include/public/trace.h b/xen/include/public/trace.h
index d5fa4aea8d..62a179971d 100644
--- a/xen/include/public/trace.h
+++ b/xen/include/public/trace.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * include/public/trace.h
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Mark Williamson, (C) 2004 Intel Research Cambridge
  * Copyright (C) 2005 Bin Ren
  */
diff --git a/xen/include/public/vcpu.h b/xen/include/public/vcpu.h
index 3623af932f..81a3b3a743 100644
--- a/xen/include/public/vcpu.h
+++ b/xen/include/public/vcpu.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * vcpu.h
  *
  * VCPU initialisation, query, and hotplug.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
  */
 
diff --git a/xen/include/public/version.h b/xen/include/public/version.h
index 17a81e23cd..9c78b4f3b6 100644
--- a/xen/include/public/version.h
+++ b/xen/include/public/version.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * version.h
  *
  * Xen version, type, and compile information.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com>
  * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
  */
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index 56b429a975..0035c26e12 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -1,27 +1,10 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * vm_event.h
  *
  * Memory event common structures.
  *
  * Copyright (c) 2009 by Citrix Systems, Inc. (Patrick Colp)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef _XEN_PUBLIC_VM_EVENT_H
diff --git a/xen/include/public/xen-compat.h b/xen/include/public/xen-compat.h
index e1c027a95c..97fe698498 100644
--- a/xen/include/public/xen-compat.h
+++ b/xen/include/public/xen-compat.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * xen-compat.h
  *
  * Guest OS interface to Xen.  Compatibility layer.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (c) 2006, Christian Limpach
  */
 
diff --git a/xen/include/public/xencomm.h b/xen/include/public/xencomm.h
index ac45e0712a..a441f3e270 100644
--- a/xen/include/public/xencomm.h
+++ b/xen/include/public/xencomm.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
 /*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) IBM Corp. 2006
  */
 
diff --git a/xen/include/public/xenoprof.h b/xen/include/public/xenoprof.h
index 9f5ca87d9e..2298b6759e 100644
--- a/xen/include/public/xenoprof.h
+++ b/xen/include/public/xenoprof.h
@@ -1,27 +1,10 @@
+/* SPDX-License-Identifier: MIT */
 /******************************************************************************
  * xenoprof.h
  *
  * Interface for enabling system wide profiling based on hardware performance
  * counters
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
  * Copyright (C) 2005 Hewlett-Packard Co.
  * Written by Aravind Menon & Jose Renato Santos
  */
diff --git a/xen/include/public/xsm/flask_op.h b/xen/include/public/xsm/flask_op.h
index b41dd6dac8..7185e80621 100644
--- a/xen/include/public/xsm/flask_op.h
+++ b/xen/include/public/xsm/flask_op.h
@@ -1,25 +1,8 @@
+/* SPDX-License-Identifier: MIT */
 /*
  *  This file contains the flask_op hypercall commands and definitions.
  *
  *  Author:  George Coker, <gscoker@alpha.ncsc.mil>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef __FLASK_OP_H__
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:11:09 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:11:09 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447724.704265 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5H-0005rC-TG; Wed, 23 Nov 2022 20:11:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447724.704265; Wed, 23 Nov 2022 20:11:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5H-0005r4-PW; Wed, 23 Nov 2022 20:11:03 +0000
Received: by outflank-mailman (input) for mailman id 447724;
 Wed, 23 Nov 2022 20:11:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5G-0005qy-FU
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5G-0006ig-Ec
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5G-000848-DY
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=tGH0McNwuK3p+RzxKIGeHO1FkD8iUhpUPcX4stJv4uI=; b=TTet408/WppwF/sYhZSI179PeO
	CE51qhC239CusctyDUnxcx1cT7Ber/lPFkMVSQtX2jFuMJ7n9vs5ZukVqE+lD2UmrLoPqS2CnIv+b
	m2+l56Yvm/FFvkVv1HGm4utyS2rixmn0XRTGeIws+/oCCllIryuS2wbHFGuQFjnDUR34=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] x86/hvm: Revert per-domain APIC acceleration support
Message-Id: <E1oxw5G-000848-DY@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:11:02 +0000

commit e5ac68a0110cb43a3a0bc17d545ae7a0bd746ef9
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Mon Nov 14 21:47:59 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Thu Nov 17 16:51:51 2022 +0000

    x86/hvm: Revert per-domain APIC acceleration support
    
    I was really hoping to avoid this, but its now too late in the 4.17 freeze and
    we still don't have working fixes.
    
    The in-Xen calculations for assistance capabilities are buggy.  For the
    avoidance of doubt, the original intention was to be able to control every
    aspect of a APIC acceleration so we could comprehensively test Xen's support,
    as it has proved to be buggy time and time again.
    
    Even after a protracted discussion on what the new API ought to mean, attempts
    to apply it to the existing logic have been unsuccessful, proving that the
    API/ABI is too complicated for most people to reason about.
    
    This reverts most of:
      2ce11ce249a3981bac50914c6a90f681ad7a4222
      6b2b9b3405092c3ad38d7342988a584b8efa674c
    
    leaving in place the non-APIC specific changes (minimal as they are).
    
    This takes us back to the behaviour of Xen 4.16 where APIC acceleration is
    configured on a per system basis.
    
    This work will be revisted in due course.
    
    Fixes: 2ce11ce249a3 ("x86/HVM: allow per-domain usage of hardware virtualized APIC")
    Fixes: 6b2b9b340509 ("x86: report Interrupt Controller Virtualization capabilities")
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 docs/man/xl.cfg.5.pod.in              | 15 ---------------
 docs/man/xl.conf.5.pod.in             | 12 ------------
 tools/golang/xenlight/helpers.gen.go  | 16 ----------------
 tools/golang/xenlight/types.gen.go    |  4 ----
 tools/include/libxl.h                 | 14 --------------
 tools/libs/light/libxl.c              |  3 ---
 tools/libs/light/libxl_arch.h         |  4 ----
 tools/libs/light/libxl_arm.c          |  5 -----
 tools/libs/light/libxl_types.idl      |  4 ----
 tools/libs/light/libxl_x86.c          | 32 --------------------------------
 tools/ocaml/libs/xc/xenctrl.ml        |  6 +-----
 tools/ocaml/libs/xc/xenctrl.mli       |  6 +-----
 tools/ocaml/libs/xc/xenctrl_stubs.c   |  7 ++-----
 tools/xl/xl.c                         |  8 --------
 tools/xl/xl.h                         |  2 --
 tools/xl/xl_info.c                    |  6 ++----
 tools/xl/xl_parse.c                   | 19 -------------------
 xen/arch/x86/domain.c                 | 23 +----------------------
 xen/arch/x86/hvm/hvm.c                |  9 ---------
 xen/arch/x86/hvm/vmx/vmcs.c           | 11 -----------
 xen/arch/x86/hvm/vmx/vmx.c            | 13 +++++++++----
 xen/arch/x86/include/asm/hvm/domain.h |  6 ------
 xen/arch/x86/include/asm/hvm/hvm.h    | 10 ----------
 xen/arch/x86/sysctl.c                 |  4 ----
 xen/arch/x86/traps.c                  |  5 ++---
 xen/include/public/arch-x86/xen.h     |  4 +---
 xen/include/public/sysctl.h           |  7 -------
 27 files changed, 19 insertions(+), 236 deletions(-)

diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index 31e58b73b0..ec444fb2ba 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -1862,21 +1862,6 @@ firmware tables when using certain older guest Operating
 Systems. These tables have been superseded by newer constructs within
 the ACPI tables.
 
-=item B<assisted_xapic=BOOLEAN>
-
-B<(x86 only)> Enables or disables hardware assisted virtualization for
-xAPIC. With this option enabled, a memory-mapped APIC access will be
-decoded by hardware and either issue a more specific VM exit than just
-a p2m fault, or altogether avoid a VM exit. The
-default is settable via L<xl.conf(5)>.
-
-=item B<assisted_x2apic=BOOLEAN>
-
-B<(x86 only)> Enables or disables hardware assisted virtualization for
-x2APIC. With this option enabled, certain accesses to MSR APIC
-registers will avoid a VM exit into the hypervisor. The default is
-settable via L<xl.conf(5)>.
-
 =item B<nx=BOOLEAN>
 
 B<(x86 only)> Hides or exposes the No-eXecute capability. This allows a guest
diff --git a/docs/man/xl.conf.5.pod.in b/docs/man/xl.conf.5.pod.in
index 95d136d1ea..df20c08137 100644
--- a/docs/man/xl.conf.5.pod.in
+++ b/docs/man/xl.conf.5.pod.in
@@ -107,18 +107,6 @@ Sets the default value for the C<max_grant_version> domain config value.
 
 Default: maximum grant version supported by the hypervisor.
 
-=item B<assisted_xapic=BOOLEAN>
-
-If enabled, domains will use xAPIC hardware assisted virtualization by default.
-
-Default: enabled if supported.
-
-=item B<assisted_x2apic=BOOLEAN>
-
-If enabled, domains will use x2APIC hardware assisted virtualization by default.
-
-Default: enabled if supported.
-
 =item B<vif.default.script="PATH">
 
 Configures the default hotplug script used by virtual network devices.
diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
index fa3cf2ab76..cb1bdf9bdf 100644
--- a/tools/golang/xenlight/helpers.gen.go
+++ b/tools/golang/xenlight/helpers.gen.go
@@ -1120,12 +1120,6 @@ x.ArchArm.Vuart = VuartType(xc.arch_arm.vuart)
 if err := x.ArchX86.MsrRelaxed.fromC(&xc.arch_x86.msr_relaxed);err != nil {
 return fmt.Errorf("converting field ArchX86.MsrRelaxed: %v", err)
 }
-if err := x.ArchX86.AssistedXapic.fromC(&xc.arch_x86.assisted_xapic);err != nil {
-return fmt.Errorf("converting field ArchX86.AssistedXapic: %v", err)
-}
-if err := x.ArchX86.AssistedX2Apic.fromC(&xc.arch_x86.assisted_x2apic);err != nil {
-return fmt.Errorf("converting field ArchX86.AssistedX2Apic: %v", err)
-}
 x.Altp2M = Altp2MMode(xc.altp2m)
 x.VmtraceBufKb = int(xc.vmtrace_buf_kb)
 if err := x.Vpmu.fromC(&xc.vpmu);err != nil {
@@ -1611,12 +1605,6 @@ xc.arch_arm.vuart = C.libxl_vuart_type(x.ArchArm.Vuart)
 if err := x.ArchX86.MsrRelaxed.toC(&xc.arch_x86.msr_relaxed); err != nil {
 return fmt.Errorf("converting field ArchX86.MsrRelaxed: %v", err)
 }
-if err := x.ArchX86.AssistedXapic.toC(&xc.arch_x86.assisted_xapic); err != nil {
-return fmt.Errorf("converting field ArchX86.AssistedXapic: %v", err)
-}
-if err := x.ArchX86.AssistedX2Apic.toC(&xc.arch_x86.assisted_x2apic); err != nil {
-return fmt.Errorf("converting field ArchX86.AssistedX2Apic: %v", err)
-}
 xc.altp2m = C.libxl_altp2m_mode(x.Altp2M)
 xc.vmtrace_buf_kb = C.int(x.VmtraceBufKb)
 if err := x.Vpmu.toC(&xc.vpmu); err != nil {
@@ -3405,8 +3393,6 @@ x.CapVmtrace = bool(xc.cap_vmtrace)
 x.CapVpmu = bool(xc.cap_vpmu)
 x.CapGnttabV1 = bool(xc.cap_gnttab_v1)
 x.CapGnttabV2 = bool(xc.cap_gnttab_v2)
-x.CapAssistedXapic = bool(xc.cap_assisted_xapic)
-x.CapAssistedX2Apic = bool(xc.cap_assisted_x2apic)
 
  return nil}
 
@@ -3441,8 +3427,6 @@ xc.cap_vmtrace = C.bool(x.CapVmtrace)
 xc.cap_vpmu = C.bool(x.CapVpmu)
 xc.cap_gnttab_v1 = C.bool(x.CapGnttabV1)
 xc.cap_gnttab_v2 = C.bool(x.CapGnttabV2)
-xc.cap_assisted_xapic = C.bool(x.CapAssistedXapic)
-xc.cap_assisted_x2apic = C.bool(x.CapAssistedX2Apic)
 
  return nil
  }
diff --git a/tools/golang/xenlight/types.gen.go b/tools/golang/xenlight/types.gen.go
index a0be7ada8c..871576fb0e 100644
--- a/tools/golang/xenlight/types.gen.go
+++ b/tools/golang/xenlight/types.gen.go
@@ -534,8 +534,6 @@ Vuart VuartType
 }
 ArchX86 struct {
 MsrRelaxed Defbool
-AssistedXapic Defbool
-AssistedX2Apic Defbool
 }
 Altp2M Altp2MMode
 VmtraceBufKb int
@@ -1036,8 +1034,6 @@ CapVmtrace bool
 CapVpmu bool
 CapGnttabV1 bool
 CapGnttabV2 bool
-CapAssistedXapic bool
-CapAssistedX2Apic bool
 }
 
 type Connectorinfo struct {
diff --git a/tools/include/libxl.h b/tools/include/libxl.h
index 2321a648a5..d652895075 100644
--- a/tools/include/libxl.h
+++ b/tools/include/libxl.h
@@ -535,20 +535,6 @@
 #define LIBXL_HAVE_DISK_TRUSTED 1
 #define LIBXL_HAVE_NIC_TRUSTED 1
 
-/*
- * LIBXL_HAVE_PHYSINFO_ASSISTED_APIC indicates that libxl_physinfo has
- * cap_assisted_xapic and cap_assisted_x2apic fields, which indicates
- * the availability of x{2}APIC hardware assisted virtualization.
- */
-#define LIBXL_HAVE_PHYSINFO_ASSISTED_APIC 1
-
-/*
- * LIBXL_HAVE_ASSISTED_APIC indicates that libxl_domain_build_info has
- * assisted_xapic and assisted_x2apic fields for enabling hardware
- * assisted virtualization for x{2}apic per domain.
- */
-#define LIBXL_HAVE_ASSISTED_APIC 1
-
 /*
  * LIBXL_HAVE_DEVICE_DISK_SPECIFICATION indicates that 'specification' and
  * 'transport' fields (of libxl_disk_specification and libxl_disk_transport
diff --git a/tools/libs/light/libxl.c b/tools/libs/light/libxl.c
index 6d699951e2..a0bf7d186f 100644
--- a/tools/libs/light/libxl.c
+++ b/tools/libs/light/libxl.c
@@ -15,7 +15,6 @@
 #include "libxl_osdeps.h"
 
 #include "libxl_internal.h"
-#include "libxl_arch.h"
 
 int libxl_ctx_alloc(libxl_ctx **pctx, int version,
                     unsigned flags, xentoollog_logger * lg)
@@ -411,8 +410,6 @@ int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
     physinfo->cap_gnttab_v2 =
         !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_gnttab_v2);
 
-    libxl__arch_get_physinfo(physinfo, &xcphysinfo);
-
     GC_FREE;
     return 0;
 }
diff --git a/tools/libs/light/libxl_arch.h b/tools/libs/light/libxl_arch.h
index 247cca130f..f88f11d6de 100644
--- a/tools/libs/light/libxl_arch.h
+++ b/tools/libs/light/libxl_arch.h
@@ -86,10 +86,6 @@ int libxl__arch_extra_memory(libxl__gc *gc,
                              const libxl_domain_build_info *info,
                              uint64_t *out);
 
-_hidden
-void libxl__arch_get_physinfo(libxl_physinfo *physinfo,
-                              const xc_physinfo_t *xcphysinfo);
-
 _hidden
 void libxl__arch_update_domain_config(libxl__gc *gc,
                                       libxl_domain_config *dst,
diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c
index 2a5e93c284..2edeaa3de6 100644
--- a/tools/libs/light/libxl_arm.c
+++ b/tools/libs/light/libxl_arm.c
@@ -1606,11 +1606,6 @@ int libxl__arch_passthrough_mode_setdefault(libxl__gc *gc,
     return rc;
 }
 
-void libxl__arch_get_physinfo(libxl_physinfo *physinfo,
-                              const xc_physinfo_t *xcphysinfo)
-{
-}
-
 void libxl__arch_update_domain_config(libxl__gc *gc,
                                       libxl_domain_config *dst,
                                       const libxl_domain_config *src)
diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl
index d634f304cd..9e3d33cb5a 100644
--- a/tools/libs/light/libxl_types.idl
+++ b/tools/libs/light/libxl_types.idl
@@ -660,8 +660,6 @@ libxl_domain_build_info = Struct("domain_build_info",[
                                ("vuart", libxl_vuart_type),
                               ])),
     ("arch_x86", Struct(None, [("msr_relaxed", libxl_defbool),
-                               ("assisted_xapic", libxl_defbool),
-                               ("assisted_x2apic", libxl_defbool),
                               ])),
     # Alternate p2m is not bound to any architecture or guest type, as it is
     # supported by x86 HVM and ARM support is planned.
@@ -1090,8 +1088,6 @@ libxl_physinfo = Struct("physinfo", [
     ("cap_vpmu", bool),
     ("cap_gnttab_v1", bool),
     ("cap_gnttab_v2", bool),
-    ("cap_assisted_xapic", bool),
-    ("cap_assisted_x2apic", bool),
     ], dir=DIR_OUT)
 
 libxl_connectorinfo = Struct("connectorinfo", [
diff --git a/tools/libs/light/libxl_x86.c b/tools/libs/light/libxl_x86.c
index 7c5ee74443..e4717f6b53 100644
--- a/tools/libs/light/libxl_x86.c
+++ b/tools/libs/light/libxl_x86.c
@@ -23,15 +23,6 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
     if (libxl_defbool_val(d_config->b_info.arch_x86.msr_relaxed))
         config->arch.misc_flags |= XEN_X86_MSR_RELAXED;
 
-    if (d_config->c_info.type != LIBXL_DOMAIN_TYPE_PV)
-    {
-        if (libxl_defbool_val(d_config->b_info.arch_x86.assisted_xapic))
-            config->arch.misc_flags |= XEN_X86_ASSISTED_XAPIC;
-
-        if (libxl_defbool_val(d_config->b_info.arch_x86.assisted_x2apic))
-            config->arch.misc_flags |= XEN_X86_ASSISTED_X2APIC;
-    }
-
     return 0;
 }
 
@@ -835,18 +826,6 @@ int libxl__arch_domain_build_info_setdefault(libxl__gc *gc,
     libxl_defbool_setdefault(&b_info->acpi, true);
     libxl_defbool_setdefault(&b_info->arch_x86.msr_relaxed, false);
 
-    if (b_info->type != LIBXL_DOMAIN_TYPE_PV) {
-        libxl_defbool_setdefault(&b_info->arch_x86.assisted_xapic,
-                                 physinfo->cap_assisted_xapic);
-        libxl_defbool_setdefault(&b_info->arch_x86.assisted_x2apic,
-                                 physinfo->cap_assisted_x2apic);
-    }
-    else if (!libxl_defbool_is_default(b_info->arch_x86.assisted_xapic) ||
-             !libxl_defbool_is_default(b_info->arch_x86.assisted_x2apic)) {
-        LOG(ERROR, "Interrupt Controller Virtualization not supported for PV");
-        return ERROR_INVAL;
-    }
-
     return 0;
 }
 
@@ -890,17 +869,6 @@ int libxl__arch_passthrough_mode_setdefault(libxl__gc *gc,
     return rc;
 }
 
-void libxl__arch_get_physinfo(libxl_physinfo *physinfo,
-                              const xc_physinfo_t *xcphysinfo)
-{
-    physinfo->cap_assisted_xapic =
-        !!(xcphysinfo->arch_capabilities &
-           XEN_SYSCTL_PHYSCAP_X86_ASSISTED_XAPIC);
-    physinfo->cap_assisted_x2apic =
-        !!(xcphysinfo->arch_capabilities &
-           XEN_SYSCTL_PHYSCAP_X86_ASSISTED_X2APIC);
-}
-
 void libxl__arch_update_domain_config(libxl__gc *gc,
                                       libxl_domain_config *dst,
                                       const libxl_domain_config *src)
diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml
index 28ed642231..83e39a8616 100644
--- a/tools/ocaml/libs/xc/xenctrl.ml
+++ b/tools/ocaml/libs/xc/xenctrl.ml
@@ -50,8 +50,6 @@ type x86_arch_emulation_flags =
 
 type x86_arch_misc_flags =
 	| X86_MSR_RELAXED
-	| X86_ASSISTED_XAPIC
-	| X86_ASSISTED_X2APIC
 
 type xen_x86_arch_domainconfig =
 {
@@ -132,9 +130,7 @@ type physinfo_cap_flag =
 
 type arm_physinfo_cap_flag
 
-type x86_physinfo_cap_flag =
-	| CAP_X86_ASSISTED_XAPIC
-	| CAP_X86_ASSISTED_X2APIC
+type x86_physinfo_cap_flag
 
 type arch_physinfo_cap_flags =
 	| ARM of arm_physinfo_cap_flag list
diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli
index c2076d60c9..5bf5f5dfea 100644
--- a/tools/ocaml/libs/xc/xenctrl.mli
+++ b/tools/ocaml/libs/xc/xenctrl.mli
@@ -44,8 +44,6 @@ type x86_arch_emulation_flags =
 
 type x86_arch_misc_flags =
   | X86_MSR_RELAXED
-  | X86_ASSISTED_XAPIC
-  | X86_ASSISTED_X2APIC
 
 type xen_x86_arch_domainconfig = {
   emulation_flags: x86_arch_emulation_flags list;
@@ -117,9 +115,7 @@ type physinfo_cap_flag =
 
 type arm_physinfo_cap_flag
 
-type x86_physinfo_cap_flag =
-  | CAP_X86_ASSISTED_XAPIC
-  | CAP_X86_ASSISTED_X2APIC
+type x86_physinfo_cap_flag
 
 type arch_physinfo_cap_flags =
   | ARM of arm_physinfo_cap_flag list
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c
index a8789d19be..f37848ae0b 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -241,7 +241,7 @@ CAMLprim value stub_xc_domain_create(value xch, value wanted_domid, value config
 
 		cfg.arch.misc_flags = ocaml_list_to_c_bitmap
 			/* ! x86_arch_misc_flags X86_ none */
-			/* ! XEN_X86_ XEN_X86_MISC_FLAGS_MAX max */
+			/* ! XEN_X86_ XEN_X86_MSR_RELAXED all */
 			(VAL_MISC_FLAGS);
 
 #undef VAL_MISC_FLAGS
@@ -748,10 +748,7 @@ CAMLprim value stub_xc_physinfo(value xch)
 	Store_field(physinfo, 9, Val_int(c_physinfo.max_cpu_id + 1));
 
 #if defined(__i386__) || defined(__x86_64__)
-	arch_cap_list = c_bitmap_to_ocaml_list
-		/* ! x86_physinfo_cap_flag CAP_X86_ none */
-		/* ! XEN_SYSCTL_PHYSCAP_X86_ XEN_SYSCTL_PHYSCAP_X86_MAX max */
-		(c_physinfo.arch_capabilities);
+	arch_cap_list = Tag_cons;
 
 	arch_cap_flags_tag = 1; /* tag x86 */
 #else
diff --git a/tools/xl/xl.c b/tools/xl/xl.c
index 31eb223309..2d1ec18ea3 100644
--- a/tools/xl/xl.c
+++ b/tools/xl/xl.c
@@ -57,8 +57,6 @@ int max_grant_frames = -1;
 int max_maptrack_frames = -1;
 int max_grant_version = LIBXL_MAX_GRANT_DEFAULT;
 libxl_domid domid_policy = INVALID_DOMID;
-int assisted_xapic = -1;
-int assisted_x2apic = -1;
 
 xentoollog_level minmsglevel = minmsglevel_default;
 
@@ -203,12 +201,6 @@ static void parse_global_config(const char *configfile,
     if (!xlu_cfg_get_long (config, "claim_mode", &l, 0))
         claim_mode = l;
 
-    if (!xlu_cfg_get_long (config, "assisted_xapic", &l, 0))
-        assisted_xapic = l;
-
-    if (!xlu_cfg_get_long (config, "assisted_x2apic", &l, 0))
-        assisted_x2apic = l;
-
     xlu_cfg_replace_string (config, "remus.default.netbufscript",
         &default_remus_netbufscript, 0);
     xlu_cfg_replace_string (config, "colo.default.proxyscript",
diff --git a/tools/xl/xl.h b/tools/xl/xl.h
index 7c9aff6ad7..72538d6a81 100644
--- a/tools/xl/xl.h
+++ b/tools/xl/xl.h
@@ -285,8 +285,6 @@ extern libxl_bitmap global_vm_affinity_mask;
 extern libxl_bitmap global_hvm_affinity_mask;
 extern libxl_bitmap global_pv_affinity_mask;
 extern libxl_domid domid_policy;
-extern int assisted_xapic;
-extern int assisted_x2apic;
 
 enum output_format {
     OUTPUT_FORMAT_JSON,
diff --git a/tools/xl/xl_info.c b/tools/xl/xl_info.c
index 3205270754..712b7638b0 100644
--- a/tools/xl/xl_info.c
+++ b/tools/xl/xl_info.c
@@ -210,7 +210,7 @@ static void output_physinfo(void)
          info.hw_cap[4], info.hw_cap[5], info.hw_cap[6], info.hw_cap[7]
         );
 
-    maybe_printf("virt_caps              :%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+    maybe_printf("virt_caps              :%s%s%s%s%s%s%s%s%s%s%s\n",
          info.cap_pv ? " pv" : "",
          info.cap_hvm ? " hvm" : "",
          info.cap_hvm && info.cap_hvm_directio ? " hvm_directio" : "",
@@ -221,9 +221,7 @@ static void output_physinfo(void)
          info.cap_vmtrace ? " vmtrace" : "",
          info.cap_vpmu ? " vpmu" : "",
          info.cap_gnttab_v1 ? " gnttab-v1" : "",
-         info.cap_gnttab_v2 ? " gnttab-v2" : "",
-         info.cap_assisted_xapic ? " assisted_xapic" : "",
-         info.cap_assisted_x2apic ? " assisted_x2apic" : ""
+         info.cap_gnttab_v2 ? " gnttab-v2" : ""
         );
 
     vinfo = libxl_get_version_info(ctx);
diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
index 1b5381cef0..644ab8f8fd 100644
--- a/tools/xl/xl_parse.c
+++ b/tools/xl/xl_parse.c
@@ -2765,25 +2765,6 @@ skip_usbdev:
 
     xlu_cfg_get_defbool(config, "vpmu", &b_info->vpmu, 0);
 
-    if (b_info->type != LIBXL_DOMAIN_TYPE_PV) {
-        e = xlu_cfg_get_long(config, "assisted_xapic", &l , 0);
-        if (!e)
-            libxl_defbool_set(&b_info->arch_x86.assisted_xapic, l);
-        else if (e != ESRCH)
-            exit(1);
-        else if (assisted_xapic != -1) /* use global default if present */
-            libxl_defbool_set(&b_info->arch_x86.assisted_xapic, assisted_xapic);
-
-        e = xlu_cfg_get_long(config, "assisted_x2apic", &l, 0);
-        if (!e)
-            libxl_defbool_set(&b_info->arch_x86.assisted_x2apic, l);
-        else if (e != ESRCH)
-            exit(1);
-        else if (assisted_x2apic != -1) /* use global default if present */
-            libxl_defbool_set(&b_info->arch_x86.assisted_x2apic,
-                              assisted_x2apic);
-    }
-
     xlu_cfg_destroy(config);
 }
 
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 79107dac69..5a119eec3a 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -49,7 +49,6 @@
 #include <asm/cpuidle.h>
 #include <asm/mpspec.h>
 #include <asm/ldt.h>
-#include <asm/hvm/domain.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/nestedhvm.h>
 #include <asm/hvm/support.h>
@@ -619,8 +618,6 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
     bool hvm = config->flags & XEN_DOMCTL_CDF_hvm;
     bool hap = config->flags & XEN_DOMCTL_CDF_hap;
     bool nested_virt = config->flags & XEN_DOMCTL_CDF_nested_virt;
-    bool assisted_xapic = config->arch.misc_flags & XEN_X86_ASSISTED_XAPIC;
-    bool assisted_x2apic = config->arch.misc_flags & XEN_X86_ASSISTED_X2APIC;
     unsigned int max_vcpus;
 
     if ( hvm ? !hvm_enabled : !IS_ENABLED(CONFIG_PV) )
@@ -687,31 +684,13 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
         }
     }
 
-    if ( config->arch.misc_flags & ~(XEN_X86_MSR_RELAXED |
-                                     XEN_X86_ASSISTED_XAPIC |
-                                     XEN_X86_ASSISTED_X2APIC) )
+    if ( config->arch.misc_flags & ~XEN_X86_MSR_RELAXED )
     {
         dprintk(XENLOG_INFO, "Invalid arch misc flags %#x\n",
                 config->arch.misc_flags);
         return -EINVAL;
     }
 
-    if ( (assisted_xapic || assisted_x2apic) && !hvm )
-    {
-        dprintk(XENLOG_INFO,
-                "Interrupt Controller Virtualization not supported for PV\n");
-        return -EINVAL;
-    }
-
-    if ( (assisted_xapic && !assisted_xapic_available) ||
-         (assisted_x2apic && !assisted_x2apic_available) )
-    {
-        dprintk(XENLOG_INFO,
-                "Hardware assisted x%sAPIC requested but not available\n",
-                assisted_xapic && !assisted_xapic_available ? "" : "2");
-        return -ENODEV;
-    }
-
     return 0;
 }
 
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 15a9b34c59..ae4368ec4b 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -117,9 +117,6 @@ static const char __initconst warning_hvm_fep[] =
 static bool_t __initdata opt_altp2m_enabled = 0;
 boolean_param("altp2m", opt_altp2m_enabled);
 
-bool __ro_after_init assisted_xapic_available;
-bool __ro_after_init assisted_x2apic_available;
-
 static int cf_check cpu_callback(
     struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
@@ -598,12 +595,6 @@ int hvm_domain_initialise(struct domain *d,
     INIT_LIST_HEAD(&d->arch.hvm.mmcfg_regions);
     INIT_LIST_HEAD(&d->arch.hvm.msix_tables);
 
-    d->arch.hvm.assisted_xapic =
-        config->arch.misc_flags & XEN_X86_ASSISTED_XAPIC;
-
-    d->arch.hvm.assisted_x2apic =
-        config->arch.misc_flags & XEN_X86_ASSISTED_X2APIC;
-
     rc = create_perdomain_mapping(d, PERDOMAIN_VIRT_START, 0, NULL, NULL);
     if ( rc )
         goto fail;
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index a1aca1ec04..84dbb88d33 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -1134,10 +1134,6 @@ static int construct_vmcs(struct vcpu *v)
         __vmwrite(PLE_WINDOW, ple_window);
     }
 
-    if ( !has_assisted_xapic(d) )
-        v->arch.hvm.vmx.secondary_exec_control &=
-            ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
-
     if ( cpu_has_vmx_secondary_exec_control )
         __vmwrite(SECONDARY_VM_EXEC_CONTROL,
                   v->arch.hvm.vmx.secondary_exec_control);
@@ -2154,14 +2150,7 @@ int __init vmx_vmcs_init(void)
     ret = _vmx_cpu_up(true);
 
     if ( !ret )
-    {
-        /* Check whether hardware supports accelerated xapic and x2apic. */
-        assisted_xapic_available = cpu_has_vmx_virtualize_apic_accesses;
-        assisted_x2apic_available = cpu_has_vmx_virtualize_x2apic_mode &&
-                                    (cpu_has_vmx_apic_reg_virt ||
-                                     cpu_has_vmx_virtual_intr_delivery);
         register_keyhandler('v', vmcs_dump, "dump VT-x VMCSs", 1);
-    }
 
     return ret;
 }
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index e624b415c9..7c81b80710 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -3405,11 +3405,16 @@ static void vmx_install_vlapic_mapping(struct vcpu *v)
 
 void vmx_vlapic_msr_changed(struct vcpu *v)
 {
+    int virtualize_x2apic_mode;
     struct vlapic *vlapic = vcpu_vlapic(v);
     unsigned int msr;
 
-    if ( !has_assisted_xapic(v->domain) &&
-         !has_assisted_x2apic(v->domain) )
+    virtualize_x2apic_mode = ( (cpu_has_vmx_apic_reg_virt ||
+                                cpu_has_vmx_virtual_intr_delivery) &&
+                               cpu_has_vmx_virtualize_x2apic_mode );
+
+    if ( !cpu_has_vmx_virtualize_apic_accesses &&
+         !virtualize_x2apic_mode )
         return;
 
     vmx_vmcs_enter(v);
@@ -3419,7 +3424,7 @@ void vmx_vlapic_msr_changed(struct vcpu *v)
     if ( !vlapic_hw_disabled(vlapic) &&
          (vlapic_base_address(vlapic) == APIC_DEFAULT_PHYS_BASE) )
     {
-        if ( has_assisted_x2apic(v->domain) && vlapic_x2apic_mode(vlapic) )
+        if ( virtualize_x2apic_mode && vlapic_x2apic_mode(vlapic) )
         {
             v->arch.hvm.vmx.secondary_exec_control |=
                 SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
@@ -3440,7 +3445,7 @@ void vmx_vlapic_msr_changed(struct vcpu *v)
                 vmx_clear_msr_intercept(v, MSR_X2APIC_SELF, VMX_MSR_W);
             }
         }
-        else if ( has_assisted_xapic(v->domain) )
+        else
             v->arch.hvm.vmx.secondary_exec_control |=
                 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
     }
diff --git a/xen/arch/x86/include/asm/hvm/domain.h b/xen/arch/x86/include/asm/hvm/domain.h
index 92bf53483c..698455444e 100644
--- a/xen/arch/x86/include/asm/hvm/domain.h
+++ b/xen/arch/x86/include/asm/hvm/domain.h
@@ -117,12 +117,6 @@ struct hvm_domain {
 
     bool                   is_s3_suspended;
 
-    /* xAPIC hardware assisted virtualization. */
-    bool                   assisted_xapic;
-
-    /* x2APIC hardware assisted virtualization. */
-    bool                   assisted_x2apic;
-
     /* hypervisor intercepted msix table */
     struct list_head       msixtbl_list;
 
diff --git a/xen/arch/x86/include/asm/hvm/hvm.h b/xen/arch/x86/include/asm/hvm/hvm.h
index 66836122e8..93254651f2 100644
--- a/xen/arch/x86/include/asm/hvm/hvm.h
+++ b/xen/arch/x86/include/asm/hvm/hvm.h
@@ -389,12 +389,6 @@ int hvm_get_param(struct domain *d, uint32_t index, uint64_t *value);
 #define hvm_tsc_scaling_ratio(d) \
     ((d)->arch.hvm.tsc_scaling_ratio)
 
-extern bool assisted_xapic_available;
-extern bool assisted_x2apic_available;
-
-#define has_assisted_xapic(d) ((d)->arch.hvm.assisted_xapic)
-#define has_assisted_x2apic(d) ((d)->arch.hvm.assisted_x2apic)
-
 #define hvm_get_guest_time(v) hvm_get_guest_time_fixed(v, 0)
 
 #define hvm_paging_enabled(v) \
@@ -908,11 +902,7 @@ static inline void hvm_set_reg(struct vcpu *v, unsigned int reg, uint64_t val)
 #define hvm_tsc_scaling_supported false
 #define hap_has_1gb false
 #define hap_has_2mb false
-#define assisted_xapic_available false
-#define assisted_x2apic_available false
 
-#define has_assisted_xapic(d) ((void)(d), false)
-#define has_assisted_x2apic(d) ((void)(d), false)
 #define hvm_paging_enabled(v) ((void)(v), false)
 #define hvm_wp_enabled(v) ((void)(v), false)
 #define hvm_pcid_enabled(v) ((void)(v), false)
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index 716525f72f..f82abc2488 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -135,10 +135,6 @@ void arch_do_physinfo(struct xen_sysctl_physinfo *pi)
         pi->capabilities |= XEN_SYSCTL_PHYSCAP_hap;
     if ( IS_ENABLED(CONFIG_SHADOW_PAGING) )
         pi->capabilities |= XEN_SYSCTL_PHYSCAP_shadow;
-    if ( assisted_xapic_available )
-        pi->arch_capabilities |= XEN_SYSCTL_PHYSCAP_X86_ASSISTED_XAPIC;
-    if ( assisted_x2apic_available )
-        pi->arch_capabilities |= XEN_SYSCTL_PHYSCAP_X86_ASSISTED_X2APIC;
 }
 
 long arch_do_sysctl(
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 56e59896bf..cade9e12f8 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -1109,8 +1109,7 @@ void cpuid_hypervisor_leaves(const struct vcpu *v, uint32_t leaf,
         if ( !is_hvm_domain(d) || subleaf != 0 )
             break;
 
-        if ( cpu_has_vmx_apic_reg_virt &&
-             has_assisted_xapic(d) )
+        if ( cpu_has_vmx_apic_reg_virt )
             res->a |= XEN_HVM_CPUID_APIC_ACCESS_VIRT;
 
         /*
@@ -1119,7 +1118,7 @@ void cpuid_hypervisor_leaves(const struct vcpu *v, uint32_t leaf,
          * and wrmsr in the guest will run without VMEXITs (see
          * vmx_vlapic_msr_changed()).
          */
-        if ( has_assisted_x2apic(d) &&
+        if ( cpu_has_vmx_virtualize_x2apic_mode &&
              cpu_has_vmx_apic_reg_virt &&
              cpu_has_vmx_virtual_intr_delivery )
             res->a |= XEN_HVM_CPUID_X2APIC_VIRT;
diff --git a/xen/include/public/arch-x86/xen.h b/xen/include/public/arch-x86/xen.h
index 93b9d600b0..c0f4551247 100644
--- a/xen/include/public/arch-x86/xen.h
+++ b/xen/include/public/arch-x86/xen.h
@@ -300,13 +300,11 @@ struct xen_arch_domainconfig {
  * doesn't allow the guest to read or write to the underlying MSR.
  */
 #define XEN_X86_MSR_RELAXED (1u << 0)
-#define XEN_X86_ASSISTED_XAPIC (1u << 1)
-#define XEN_X86_ASSISTED_X2APIC (1u << 2)
     uint32_t misc_flags;
 };
 
 /* Max  XEN_X86_* constant. Used for ABI checking. */
-#define XEN_X86_MISC_FLAGS_MAX XEN_X86_ASSISTED_X2APIC
+#define XEN_X86_MISC_FLAGS_MAX XEN_X86_MSR_RELAXED
 
 #endif
 
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index 051bff39b3..001a4de273 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -94,13 +94,6 @@ struct xen_sysctl_tbuf_op {
 /* Max XEN_SYSCTL_PHYSCAP_* constant.  Used for ABI checking. */
 #define XEN_SYSCTL_PHYSCAP_MAX XEN_SYSCTL_PHYSCAP_gnttab_v2
 
-/* The platform supports x{2}apic hardware assisted emulation. */
-#define XEN_SYSCTL_PHYSCAP_X86_ASSISTED_XAPIC  (1u << 0)
-#define XEN_SYSCTL_PHYSCAP_X86_ASSISTED_X2APIC (1u << 1)
-
-/* Max XEN_SYSCTL_PHYSCAP_X86_* constant. Used for ABI checking. */
-#define XEN_SYSCTL_PHYSCAP_X86_MAX XEN_SYSCTL_PHYSCAP_X86_ASSISTED_X2APIC
-
 struct xen_sysctl_physinfo {
     uint32_t threads_per_core;
     uint32_t cores_per_socket;
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:11:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:11:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447725.704269 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5R-0005th-08; Wed, 23 Nov 2022 20:11:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447725.704269; Wed, 23 Nov 2022 20:11:12 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5Q-0005tZ-Sw; Wed, 23 Nov 2022 20:11:12 +0000
Received: by outflank-mailman (input) for mailman id 447725;
 Wed, 23 Nov 2022 20:11:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5Q-0005tR-Jt
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5Q-0006in-Ic
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5Q-00084a-HW
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=6pZAg/wE+ku4lSqeP2Lw3PAin7rRItqIMxc+mDhSpsI=; b=rCN8F9gclkdQZY2uybB5VzXG+1
	YcXErE5GG8pDCA4hAQ+GAMagcgv1JVlGMC397DKj1APToM477sN5QFEbONFWcwVE1Z5qpRGlT5nLH
	rAJ6FYBkChb/Lnj3+4DJiNKME1rcZ29UjKe3wiIXN/eC7MpvIvNTQ9CFXry0vmOGkT8c=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen: Introduce non-broken hypercalls for the paging mempool size
Message-Id: <E1oxw5Q-00084a-HW@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:11:12 +0000

commit 22b20bd98c025e06525410e3ab3494d5e63489f7
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Fri Oct 21 14:13:00 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Thu Nov 17 16:51:51 2022 +0000

    xen: Introduce non-broken hypercalls for the paging mempool size
    
    The existing XEN_DOMCTL_SHADOW_OP_{GET,SET}_ALLOCATION have problems:
    
     * All set_allocation() flavours have an overflow-before-widen bug when
       calculating "sc->mb << (20 - PAGE_SHIFT)".
     * All flavours have a granularity of 1M.  This was tolerable when the size of
       the pool could only be set at the same granularity, but is broken now that
       ARM has a 16-page stopgap allocation in use.
     * All get_allocation() flavours round up, and in particular turn 0 into 1,
       meaning the get op returns junk before a successful set op.
     * The x86 flavours reject the hypercalls before the VM has vCPUs allocated,
       despite the pool size being a domain property.
     * Even the hypercall names are long-obsolete.
    
    Implement a better interface, which can be first used to unit test the
    behaviour, and subsequently correct a broken implementation.  The old
    interface will be retired in due course.
    
    The unit of bytes (as opposed pages) is a deliberate API/ABI improvement to
    more easily support multiple page granularities.
    
    This is part of XSA-409 / CVE-2022-33747.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Anthony PERARD <anthony.perard@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/include/xenctrl.h           |  3 +++
 tools/libs/ctrl/xc_domain.c       | 29 ++++++++++++++++++++++++++
 xen/arch/arm/p2m.c                | 26 +++++++++++++++++++++++
 xen/arch/x86/include/asm/hap.h    |  1 +
 xen/arch/x86/include/asm/shadow.h |  4 ++++
 xen/arch/x86/mm/hap/hap.c         | 11 ++++++++++
 xen/arch/x86/mm/paging.c          | 43 +++++++++++++++++++++++++++++++++++++++
 xen/arch/x86/mm/shadow/common.c   | 11 ++++++++++
 xen/common/domctl.c               | 14 +++++++++++++
 xen/include/public/domctl.h       | 24 +++++++++++++++++++++-
 xen/include/xen/domain.h          |  3 +++
 11 files changed, 168 insertions(+), 1 deletion(-)

diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h
index 0c8b4c3aa7..23037874d3 100644
--- a/tools/include/xenctrl.h
+++ b/tools/include/xenctrl.h
@@ -893,6 +893,9 @@ long long xc_logdirty_control(xc_interface *xch,
                               unsigned int mode,
                               xc_shadow_op_stats_t *stats);
 
+int xc_get_paging_mempool_size(xc_interface *xch, uint32_t domid, uint64_t *size);
+int xc_set_paging_mempool_size(xc_interface *xch, uint32_t domid, uint64_t size);
+
 int xc_sched_credit_domain_set(xc_interface *xch,
                                uint32_t domid,
                                struct xen_domctl_sched_credit *sdom);
diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c
index 14c0420c35..e939d07157 100644
--- a/tools/libs/ctrl/xc_domain.c
+++ b/tools/libs/ctrl/xc_domain.c
@@ -706,6 +706,35 @@ long long xc_logdirty_control(xc_interface *xch,
     return (rc == 0) ? domctl.u.shadow_op.pages : rc;
 }
 
+int xc_get_paging_mempool_size(xc_interface *xch, uint32_t domid, uint64_t *size)
+{
+    int rc;
+    struct xen_domctl domctl = {
+        .cmd         = XEN_DOMCTL_get_paging_mempool_size,
+        .domain      = domid,
+    };
+
+    rc = do_domctl(xch, &domctl);
+    if ( rc )
+        return rc;
+
+    *size = domctl.u.paging_mempool.size;
+    return 0;
+}
+
+int xc_set_paging_mempool_size(xc_interface *xch, uint32_t domid, uint64_t size)
+{
+    struct xen_domctl domctl = {
+        .cmd         = XEN_DOMCTL_set_paging_mempool_size,
+        .domain      = domid,
+        .u.paging_mempool = {
+            .size = size,
+        },
+    };
+
+    return do_domctl(xch, &domctl);
+}
+
 int xc_domain_setmaxmem(xc_interface *xch,
                         uint32_t domid,
                         uint64_t max_memkb)
diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 94d3b60b13..8c1972e582 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -100,6 +100,13 @@ unsigned int p2m_get_allocation(struct domain *d)
     return ROUNDUP(nr_pages, 1 << (20 - PAGE_SHIFT)) >> (20 - PAGE_SHIFT);
 }
 
+/* Return the size of the pool, in bytes. */
+int arch_get_paging_mempool_size(struct domain *d, uint64_t *size)
+{
+    *size = (uint64_t)ACCESS_ONCE(d->arch.paging.p2m_total_pages) << PAGE_SHIFT;
+    return 0;
+}
+
 /*
  * Set the pool of pages to the required number of pages.
  * Returns 0 for success, non-zero for failure.
@@ -157,6 +164,25 @@ int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted)
     return 0;
 }
 
+int arch_set_paging_mempool_size(struct domain *d, uint64_t size)
+{
+    unsigned long pages = size >> PAGE_SHIFT;
+    bool preempted = false;
+    int rc;
+
+    if ( (size & ~PAGE_MASK) ||          /* Non page-sized request? */
+         pages != (size >> PAGE_SHIFT) ) /* 32-bit overflow? */
+        return -EINVAL;
+
+    spin_lock(&d->arch.paging.lock);
+    rc = p2m_set_allocation(d, pages, &preempted);
+    spin_unlock(&d->arch.paging.lock);
+
+    ASSERT(preempted == (rc == -ERESTART));
+
+    return rc;
+}
+
 int p2m_teardown_allocation(struct domain *d)
 {
     int ret = 0;
diff --git a/xen/arch/x86/include/asm/hap.h b/xen/arch/x86/include/asm/hap.h
index 90dece29de..14d2f212da 100644
--- a/xen/arch/x86/include/asm/hap.h
+++ b/xen/arch/x86/include/asm/hap.h
@@ -47,6 +47,7 @@ int   hap_track_dirty_vram(struct domain *d,
 extern const struct paging_mode *hap_paging_get_mode(struct vcpu *);
 int hap_set_allocation(struct domain *d, unsigned int pages, bool *preempted);
 unsigned int hap_get_allocation(struct domain *d);
+int hap_get_allocation_bytes(struct domain *d, uint64_t *size);
 
 #endif /* XEN_HAP_H */
 
diff --git a/xen/arch/x86/include/asm/shadow.h b/xen/arch/x86/include/asm/shadow.h
index 1365fe4805..dad876d294 100644
--- a/xen/arch/x86/include/asm/shadow.h
+++ b/xen/arch/x86/include/asm/shadow.h
@@ -97,6 +97,8 @@ void shadow_blow_tables_per_domain(struct domain *d);
 int shadow_set_allocation(struct domain *d, unsigned int pages,
                           bool *preempted);
 
+int shadow_get_allocation_bytes(struct domain *d, uint64_t *size);
+
 #else /* !CONFIG_SHADOW_PAGING */
 
 #define shadow_vcpu_teardown(v) ASSERT(is_pv_vcpu(v))
@@ -108,6 +110,8 @@ int shadow_set_allocation(struct domain *d, unsigned int pages,
     ({ ASSERT_UNREACHABLE(); -EOPNOTSUPP; })
 #define shadow_set_allocation(d, pages, preempted) \
     ({ ASSERT_UNREACHABLE(); -EOPNOTSUPP; })
+#define shadow_get_allocation_bytes(d, size) \
+    ({ ASSERT_UNREACHABLE(); -EOPNOTSUPP; })
 
 static inline void sh_remove_shadows(struct domain *d, mfn_t gmfn,
                                      int fast, int all) {}
diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c
index f809ea9aa6..0fc1b1d9ac 100644
--- a/xen/arch/x86/mm/hap/hap.c
+++ b/xen/arch/x86/mm/hap/hap.c
@@ -345,6 +345,17 @@ unsigned int hap_get_allocation(struct domain *d)
             + ((pg & ((1 << (20 - PAGE_SHIFT)) - 1)) ? 1 : 0));
 }
 
+int hap_get_allocation_bytes(struct domain *d, uint64_t *size)
+{
+    unsigned long pages = d->arch.paging.hap.total_pages;
+
+    pages += d->arch.paging.hap.p2m_pages;
+
+    *size = pages << PAGE_SHIFT;
+
+    return 0;
+}
+
 /* Set the pool of pages to the required number of pages.
  * Returns 0 for success, non-zero for failure. */
 int hap_set_allocation(struct domain *d, unsigned int pages, bool *preempted)
diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c
index 3a355eee9c..8d579fa9a3 100644
--- a/xen/arch/x86/mm/paging.c
+++ b/xen/arch/x86/mm/paging.c
@@ -977,6 +977,49 @@ int __init paging_set_allocation(struct domain *d, unsigned int pages,
 }
 #endif
 
+int arch_get_paging_mempool_size(struct domain *d, uint64_t *size)
+{
+    int rc;
+
+    if ( is_pv_domain(d) )                 /* TODO: Relax in due course */
+        return -EOPNOTSUPP;
+
+    if ( hap_enabled(d) )
+        rc = hap_get_allocation_bytes(d, size);
+    else
+        rc = shadow_get_allocation_bytes(d, size);
+
+    return rc;
+}
+
+int arch_set_paging_mempool_size(struct domain *d, uint64_t size)
+{
+    unsigned long pages = size >> PAGE_SHIFT;
+    bool preempted = false;
+    int rc;
+
+    if ( is_pv_domain(d) )                 /* TODO: Relax in due course */
+        return -EOPNOTSUPP;
+
+    if ( size & ~PAGE_MASK ||              /* Non page-sized request? */
+         pages != (unsigned int)pages )    /* Overflow $X_set_allocation()? */
+        return -EINVAL;
+
+    paging_lock(d);
+    if ( hap_enabled(d) )
+        rc = hap_set_allocation(d, pages, &preempted);
+    else
+        rc = shadow_set_allocation(d, pages, &preempted);
+    paging_unlock(d);
+
+    /*
+     * TODO: Adjust $X_set_allocation() so this is true.
+    ASSERT(preempted == (rc == -ERESTART));
+     */
+
+    return preempted ? -ERESTART : rc;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index badfd53c6b..a8404f97f6 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -1427,6 +1427,17 @@ static unsigned int shadow_get_allocation(struct domain *d)
             + ((pg & ((1 << (20 - PAGE_SHIFT)) - 1)) ? 1 : 0));
 }
 
+int shadow_get_allocation_bytes(struct domain *d, uint64_t *size)
+{
+    unsigned long pages = d->arch.paging.shadow.total_pages;
+
+    pages += d->arch.paging.shadow.p2m_pages;
+
+    *size = pages << PAGE_SHIFT;
+
+    return 0;
+}
+
 /**************************************************************************/
 /* Hash table for storing the guest->shadow mappings.
  * The table itself is an array of pointers to shadows; the shadows are then
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 69fb9abd34..ad71ad8a4c 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -874,6 +874,20 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
         ret = iommu_do_domctl(op, d, u_domctl);
         break;
 
+    case XEN_DOMCTL_get_paging_mempool_size:
+        ret = arch_get_paging_mempool_size(d, &op->u.paging_mempool.size);
+        if ( !ret )
+            copyback = 1;
+        break;
+
+    case XEN_DOMCTL_set_paging_mempool_size:
+        ret = arch_set_paging_mempool_size(d, op->u.paging_mempool.size);
+
+        if ( ret == -ERESTART )
+            ret = hypercall_create_continuation(
+                __HYPERVISOR_domctl, "h", u_domctl);
+        break;
+
     default:
         ret = arch_do_domctl(op, d, u_domctl);
         break;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 966bf4323c..51be28c3de 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -197,7 +197,10 @@ struct xen_domctl_getpageframeinfo3 {
  /* Return the bitmap but do not modify internal copy. */
 #define XEN_DOMCTL_SHADOW_OP_PEEK        12
 
-/* Memory allocation accessors. */
+/*
+ * Memory allocation accessors.  These APIs are broken and will be removed.
+ * Use XEN_DOMCTL_{get,set}_paging_mempool_size instead.
+ */
 #define XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION   30
 #define XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION   31
 
@@ -929,6 +932,22 @@ struct xen_domctl_cacheflush {
     xen_pfn_t start_pfn, nr_pfns;
 };
 
+/*
+ * XEN_DOMCTL_get_paging_mempool_size / XEN_DOMCTL_set_paging_mempool_size.
+ *
+ * Get or set the paging memory pool size.  The size is in bytes.
+ *
+ * This is a dedicated pool of memory for Xen to use while managing the guest,
+ * typically containing pagetables.  As such, there is an implementation
+ * specific minimum granularity.
+ *
+ * The set operation can fail mid-way through the request (e.g. Xen running
+ * out of memory, no free memory to reclaim from the pool, etc.).
+ */
+struct xen_domctl_paging_mempool {
+    uint64_aligned_t size; /* Size in bytes. */
+};
+
 #if defined(__i386__) || defined(__x86_64__)
 struct xen_domctl_vcpu_msr {
     uint32_t         index;
@@ -1257,6 +1276,8 @@ struct xen_domctl {
 #define XEN_DOMCTL_get_cpu_policy                82
 #define XEN_DOMCTL_set_cpu_policy                83
 #define XEN_DOMCTL_vmtrace_op                    84
+#define XEN_DOMCTL_get_paging_mempool_size       85
+#define XEN_DOMCTL_set_paging_mempool_size       86
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1318,6 +1339,7 @@ struct xen_domctl {
         struct xen_domctl_psr_alloc         psr_alloc;
         struct xen_domctl_vuart_op          vuart_op;
         struct xen_domctl_vmtrace_op        vmtrace_op;
+        struct xen_domctl_paging_mempool    paging_mempool;
         uint8_t                             pad[128];
     } u;
 };
diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
index 2c8116afba..0de9cbc169 100644
--- a/xen/include/xen/domain.h
+++ b/xen/include/xen/domain.h
@@ -98,6 +98,9 @@ void arch_get_info_guest(struct vcpu *, vcpu_guest_context_u);
 int arch_initialise_vcpu(struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg);
 int default_initialise_vcpu(struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg);
 
+int arch_get_paging_mempool_size(struct domain *d, uint64_t *size /* bytes */);
+int arch_set_paging_mempool_size(struct domain *d, uint64_t size /* bytes */);
+
 int domain_relinquish_resources(struct domain *d);
 
 void dump_pageframe_info(struct domain *d);
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:11:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:11:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447726.704273 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5b-0005wW-1A; Wed, 23 Nov 2022 20:11:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447726.704273; Wed, 23 Nov 2022 20:11:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5a-0005wO-UY; Wed, 23 Nov 2022 20:11:22 +0000
Received: by outflank-mailman (input) for mailman id 447726;
 Wed, 23 Nov 2022 20:11:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5a-0005wI-Ne
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5a-0006jN-Mu
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5a-000857-L1
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=qCVbY3dHCDaIHrui3yQQRlKPLse2j+rTI/xfBEDBGaY=; b=UQF5ed9pFRc8o8YIJfY/IrlYjT
	9UDIKkGa2TCiKWN9xE/lXWQiFbcrqkEIgC+pj17QfDEr5KxqDeoBc7IIH1WNyJWB6TBGGjYuyRe7C
	Nl0P5FH1p0tzqklfpBIwtbemLQYMF3WJ5Wb3FyDSFIDkyYkJvFcBDu0OXYiMRZ+qnLWc=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/tests: Unit test for paging mempool size
Message-Id: <E1oxw5a-000857-L1@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:11:22 +0000

commit bd87315a603bf25e869e6293f7db7b1024d67999
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Thu Oct 20 12:13:46 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Thu Nov 17 16:51:51 2022 +0000

    tools/tests: Unit test for paging mempool size
    
    Exercise some basic functionality of the new
    xc_{get,set}_paging_mempool_size() hypercalls.
    
    This passes on x86, but fails currently on ARM.  ARM will be fixed up in
    future patches.
    
    This is part of XSA-409 / CVE-2022-33747.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    Acked-by: Anthony PERARD <anthony.perard@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/tests/Makefile                             |   1 +
 tools/tests/paging-mempool/.gitignore            |   1 +
 tools/tests/paging-mempool/Makefile              |  38 +++++
 tools/tests/paging-mempool/test-paging-mempool.c | 181 +++++++++++++++++++++++
 4 files changed, 221 insertions(+)

diff --git a/tools/tests/Makefile b/tools/tests/Makefile
index d99146d56a..1319c3a9d8 100644
--- a/tools/tests/Makefile
+++ b/tools/tests/Makefile
@@ -11,6 +11,7 @@ endif
 SUBDIRS-y += xenstore
 SUBDIRS-y += depriv
 SUBDIRS-y += vpci
+SUBDIRS-y += paging-mempool
 
 .PHONY: all clean install distclean uninstall
 all clean distclean install uninstall: %: subdirs-%
diff --git a/tools/tests/paging-mempool/.gitignore b/tools/tests/paging-mempool/.gitignore
new file mode 100644
index 0000000000..2f9305b7cc
--- /dev/null
+++ b/tools/tests/paging-mempool/.gitignore
@@ -0,0 +1 @@
+test-paging-mempool
diff --git a/tools/tests/paging-mempool/Makefile b/tools/tests/paging-mempool/Makefile
new file mode 100644
index 0000000000..a081b3baa5
--- /dev/null
+++ b/tools/tests/paging-mempool/Makefile
@@ -0,0 +1,38 @@
+XEN_ROOT = $(CURDIR)/../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+TARGET := test-paging-mempool
+
+.PHONY: all
+all: $(TARGET)
+
+.PHONY: clean
+clean:
+	$(RM) -- *.o $(TARGET) $(DEPS_RM)
+
+.PHONY: distclean
+distclean: clean
+	$(RM) -- *~
+
+.PHONY: install
+install: all
+	$(INSTALL_DIR) $(DESTDIR)$(LIBEXEC_BIN)
+	$(INSTALL_PROG) $(TARGET) $(DESTDIR)$(LIBEXEC_BIN)
+
+.PHONY: uninstall
+uninstall:
+	$(RM) -- $(DESTDIR)$(LIBEXEC_BIN)/$(TARGET)
+
+CFLAGS += $(CFLAGS_xeninclude)
+CFLAGS += $(CFLAGS_libxenctrl)
+CFLAGS += $(APPEND_CFLAGS)
+
+LDFLAGS += $(LDLIBS_libxenctrl)
+LDFLAGS += $(APPEND_LDFLAGS)
+
+%.o: Makefile
+
+$(TARGET): test-paging-mempool.o
+	$(CC) -o $@ $< $(LDFLAGS)
+
+-include $(DEPS_INCLUDE)
diff --git a/tools/tests/paging-mempool/test-paging-mempool.c b/tools/tests/paging-mempool/test-paging-mempool.c
new file mode 100644
index 0000000000..b2dfe9b074
--- /dev/null
+++ b/tools/tests/paging-mempool/test-paging-mempool.c
@@ -0,0 +1,181 @@
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <xenctrl.h>
+#include <xenforeignmemory.h>
+#include <xengnttab.h>
+#include <xen-tools/libs.h>
+
+static unsigned int nr_failures;
+#define fail(fmt, ...)                          \
+({                                              \
+    nr_failures++;                              \
+    (void)printf(fmt, ##__VA_ARGS__);           \
+})
+
+static xc_interface *xch;
+static uint32_t domid;
+
+static struct xen_domctl_createdomain create = {
+    .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
+    .max_vcpus = 1,
+    .max_grant_frames = 1,
+    .grant_opts = XEN_DOMCTL_GRANT_version(1),
+
+    .arch = {
+#if defined(__x86_64__) || defined(__i386__)
+        .emulation_flags = XEN_X86_EMU_LAPIC,
+#endif
+    },
+};
+
+static uint64_t default_mempool_size_bytes =
+#if defined(__x86_64__) || defined(__i386__)
+    256 << 12; /* Only x86 HAP for now.  x86 Shadow needs more work. */
+#elif defined (__arm__) || defined(__aarch64__)
+    16 << 12;
+#endif
+
+static void run_tests(void)
+{
+    xen_pfn_t physmap[] = { 0 };
+    uint64_t size_bytes, old_size_bytes;
+    int rc;
+
+    printf("Test default mempool size\n");
+
+    rc = xc_get_paging_mempool_size(xch, domid, &size_bytes);
+    if ( rc )
+        return fail("  Fail: get mempool size: %d - %s\n",
+                    errno, strerror(errno));
+
+    printf("mempool size %"PRIu64" bytes (%"PRIu64"kB, %"PRIu64"MB)\n",
+           size_bytes, size_bytes >> 10, size_bytes >> 20);
+
+
+    /*
+     * Check that the domain has the expected default allocation size.  This
+     * will fail if the logic in Xen is altered without an equivalent
+     * adjustment here.
+     */
+    if ( size_bytes != default_mempool_size_bytes )
+        return fail("  Fail: size %"PRIu64" != expected size %"PRIu64"\n",
+                    size_bytes, default_mempool_size_bytes);
+
+
+    printf("Test that allocate doesn't alter pool size\n");
+
+    /*
+     * Populate the domain with some RAM.  This will cause more of the mempool
+     * to be used.
+     */
+    old_size_bytes = size_bytes;
+
+    rc = xc_domain_setmaxmem(xch, domid, -1);
+    if ( rc )
+        return fail("  Fail: setmaxmem: : %d - %s\n",
+                    errno, strerror(errno));
+
+    rc = xc_domain_populate_physmap_exact(xch, domid, 1, 0, 0, physmap);
+    if ( rc )
+        return fail("  Fail: populate physmap: %d - %s\n",
+                    errno, strerror(errno));
+
+    /*
+     * Re-get the p2m size.  Should not have changed as a consequence of
+     * populate physmap.
+     */
+    rc = xc_get_paging_mempool_size(xch, domid, &size_bytes);
+    if ( rc )
+        return fail("  Fail: get mempool size: %d - %s\n",
+                    errno, strerror(errno));
+
+    if ( old_size_bytes != size_bytes )
+        return fail("  Fail: mempool size changed %"PRIu64" => %"PRIu64"\n",
+                    old_size_bytes, size_bytes);
+
+
+
+    printf("Test bad set size\n");
+
+    /*
+     * Check that setting a non-page size results in failure.
+     */
+    rc = xc_set_paging_mempool_size(xch, domid, size_bytes + 1);
+    if ( rc != -1 || errno != EINVAL )
+        return fail("  Fail: Bad set size: expected -1/EINVAL, got %d/%d - %s\n",
+                    rc, errno, strerror(errno));
+
+
+    printf("Test set continuation\n");
+
+    /*
+     * Check that setting a large P2M size succeeds.  This is expecting to
+     * trigger continuations.
+     */
+    rc = xc_set_paging_mempool_size(xch, domid, 64 << 20);
+    if ( rc )
+        return fail("  Fail: Set size 64MB: %d - %s\n",
+                    errno, strerror(errno));
+
+
+    /*
+     * Check that the reported size matches what set consumed.
+     */
+    rc = xc_get_paging_mempool_size(xch, domid, &size_bytes);
+    if ( rc )
+        return fail("  Fail: get p2m mempool size: %d - %s\n",
+                    errno, strerror(errno));
+
+    if ( size_bytes != 64 << 20 )
+        return fail("  Fail: expected mempool size %u, got %"PRIu64"\n",
+                    64 << 20, size_bytes);
+}
+
+int main(int argc, char **argv)
+{
+    int rc;
+
+    printf("Paging mempool tests\n");
+
+    xch = xc_interface_open(NULL, NULL, 0);
+
+    if ( !xch )
+        err(1, "xc_interface_open");
+
+    rc = xc_domain_create(xch, &domid, &create);
+    if ( rc )
+    {
+        if ( errno == EINVAL || errno == EOPNOTSUPP )
+            printf("  Skip: %d - %s\n", errno, strerror(errno));
+        else
+            fail("  Domain create failure: %d - %s\n",
+                 errno, strerror(errno));
+        goto out;
+    }
+
+    printf("  Created d%u\n", domid);
+
+    run_tests();
+
+    rc = xc_domain_destroy(xch, domid);
+    if ( rc )
+        fail("  Failed to destroy domain: %d - %s\n",
+             errno, strerror(errno));
+ out:
+    return !!nr_failures;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:11:34 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:11:34 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447727.704276 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5m-0005zA-2P; Wed, 23 Nov 2022 20:11:34 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447727.704276; Wed, 23 Nov 2022 20:11:34 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5l-0005z3-W9; Wed, 23 Nov 2022 20:11:33 +0000
Received: by outflank-mailman (input) for mailman id 447727;
 Wed, 23 Nov 2022 20:11:32 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5k-0005yl-RA
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:32 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5k-0006jX-QS
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:32 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5k-00085s-Pa
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:32 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=fBkCrGL8YtsbqVcz7OAjJc/8juspSPUzgximrlF3yDc=; b=tEBY2Owb60/7gJn+USTZawwmQ5
	KIx/69RjN0mXVSGhZpckkPl+m1DFp6nKoX7ZXx3lGJ0UKzkLJSCC7obSXbl2gEuxOFLcGFgEvOQs7
	IyRDPYPX5Q9Aa0E7ZxEMFc9lYSfK/S0VEibIP6zQMYGUzhuVcp5uQ8SnuW7HiPCG/3a8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen/arm, libxl: Revert XEN_DOMCTL_shadow_op; use p2m mempool hypercalls
Message-Id: <E1oxw5k-00085s-Pa@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:11:32 +0000

commit 7c3bbd940dd8aeb1649734e5055798cc6f3fea4e
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Tue Oct 25 15:27:05 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Thu Nov 17 16:51:51 2022 +0000

    xen/arm, libxl: Revert XEN_DOMCTL_shadow_op; use p2m mempool hypercalls
    
    This reverts most of commit cf2a68d2ffbc3ce95e01449d46180bddb10d24a0, and bits
    of cbea5a1149ca7fd4b7cdbfa3ec2e4f109b601ff7.
    
    First of all, with ARM borrowing x86's implementation, the logic to set the
    pool size should have been common, not duplicated.  Introduce
    libxl__domain_set_paging_mempool_size() as a shared implementation, and use it
    from the ARM and x86 paths.  It is left as an exercise to the reader to judge
    how libxl/xl can reasonably function without the ability to query the pool
    size...
    
    Remove ARM's p2m_domctl() infrastructure now the functioanlity has been
    replaced with a working and unit tested interface.
    
    This is part of XSA-409 / CVE-2022-33747.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
    Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/libs/light/libxl_arm.c      | 14 +----------
 tools/libs/light/libxl_dom.c      | 18 +++++++++++++
 tools/libs/light/libxl_internal.h |  3 +++
 tools/libs/light/libxl_x86.c      | 15 ++---------
 xen/arch/arm/domctl.c             | 53 ---------------------------------------
 xen/arch/arm/include/asm/p2m.h    |  1 -
 xen/arch/arm/p2m.c                |  8 ------
 7 files changed, 24 insertions(+), 88 deletions(-)

diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c
index 2edeaa3de6..cd84a7c66e 100644
--- a/tools/libs/light/libxl_arm.c
+++ b/tools/libs/light/libxl_arm.c
@@ -209,19 +209,7 @@ int libxl__arch_domain_create(libxl__gc *gc,
                               libxl__domain_build_state *state,
                               uint32_t domid)
 {
-    libxl_ctx *ctx = libxl__gc_owner(gc);
-    unsigned int shadow_mb = DIV_ROUNDUP(d_config->b_info.shadow_memkb, 1024);
-
-    int r = xc_shadow_control(ctx->xch, domid,
-                              XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION,
-                              &shadow_mb, 0);
-    if (r) {
-        LOGED(ERROR, domid,
-              "Failed to set %u MiB shadow allocation", shadow_mb);
-        return ERROR_FAIL;
-    }
-
-    return 0;
+    return libxl__domain_set_paging_mempool_size(gc, d_config, domid);
 }
 
 int libxl__arch_extra_memory(libxl__gc *gc,
diff --git a/tools/libs/light/libxl_dom.c b/tools/libs/light/libxl_dom.c
index 2abaab439c..b59bbe00bb 100644
--- a/tools/libs/light/libxl_dom.c
+++ b/tools/libs/light/libxl_dom.c
@@ -1448,6 +1448,24 @@ out:
     return rc;
 }
 
+int libxl__domain_set_paging_mempool_size(
+    libxl__gc *gc, libxl_domain_config *d_config, uint32_t domid)
+{
+    uint64_t shadow_mem;
+
+    shadow_mem = d_config->b_info.shadow_memkb;
+    shadow_mem <<= 10;
+
+    int r = xc_set_paging_mempool_size(CTX->xch, domid, shadow_mem);
+    if (r) {
+        LOGED(ERROR, domid,
+              "Failed to set paging mempool size to %"PRIu64"kB", shadow_mem);
+        return ERROR_FAIL;
+    }
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h
index cb9e8b3b8b..a7c447c10e 100644
--- a/tools/libs/light/libxl_internal.h
+++ b/tools/libs/light/libxl_internal.h
@@ -4864,6 +4864,9 @@ int libxl__is_domid_recent(libxl__gc *gc, uint32_t domid, bool *recent);
 /* os-specific implementation of setresuid() */
 int libxl__setresuid(uid_t ruid, uid_t euid, uid_t suid);
 
+_hidden int libxl__domain_set_paging_mempool_size(
+    libxl__gc *gc, libxl_domain_config *d_config, uint32_t domid);
+
 #endif
 
 /*
diff --git a/tools/libs/light/libxl_x86.c b/tools/libs/light/libxl_x86.c
index e4717f6b53..7484a5745e 100644
--- a/tools/libs/light/libxl_x86.c
+++ b/tools/libs/light/libxl_x86.c
@@ -529,20 +529,9 @@ int libxl__arch_domain_create(libxl__gc *gc,
         xc_domain_set_time_offset(ctx->xch, domid, rtc_timeoffset);
 
     if (d_config->b_info.type != LIBXL_DOMAIN_TYPE_PV) {
-        unsigned int shadow_mb = DIV_ROUNDUP(d_config->b_info.shadow_memkb,
-                                             1024);
-        int r = xc_shadow_control(ctx->xch, domid,
-                                  XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION,
-                                  &shadow_mb, 0);
-
-        if (r) {
-            LOGED(ERROR, domid,
-                  "Failed to set %u MiB %s allocation",
-                  shadow_mb,
-                  libxl_defbool_val(d_config->c_info.hap) ? "HAP" : "shadow");
-            ret = ERROR_FAIL;
+        ret = libxl__domain_set_paging_mempool_size(gc, d_config, domid);
+        if (ret)
             goto out;
-        }
     }
 
     if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV &&
diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
index c8fdeb1240..1baf25c3d9 100644
--- a/xen/arch/arm/domctl.c
+++ b/xen/arch/arm/domctl.c
@@ -47,64 +47,11 @@ static int handle_vuart_init(struct domain *d,
     return rc;
 }
 
-static long p2m_domctl(struct domain *d, struct xen_domctl_shadow_op *sc,
-                       XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
-{
-    long rc;
-    bool preempted = false;
-
-    if ( unlikely(d == current->domain) )
-    {
-        printk(XENLOG_ERR "Tried to do a p2m domctl op on itself.\n");
-        return -EINVAL;
-    }
-
-    if ( unlikely(d->is_dying) )
-    {
-        printk(XENLOG_ERR "Tried to do a p2m domctl op on dying domain %u\n",
-               d->domain_id);
-        return -EINVAL;
-    }
-
-    switch ( sc->op )
-    {
-    case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION:
-    {
-        /* Allow and handle preemption */
-        spin_lock(&d->arch.paging.lock);
-        rc = p2m_set_allocation(d, sc->mb << (20 - PAGE_SHIFT), &preempted);
-        spin_unlock(&d->arch.paging.lock);
-
-        if ( preempted )
-            /* Not finished. Set up to re-run the call. */
-            rc = hypercall_create_continuation(__HYPERVISOR_domctl, "h",
-                                               u_domctl);
-        else
-            /* Finished. Return the new allocation. */
-            sc->mb = p2m_get_allocation(d);
-
-        return rc;
-    }
-    case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION:
-    {
-        sc->mb = p2m_get_allocation(d);
-        return 0;
-    }
-    default:
-    {
-        printk(XENLOG_ERR "Bad p2m domctl op %u\n", sc->op);
-        return -EINVAL;
-    }
-    }
-}
-
 long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
                     XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
 {
     switch ( domctl->cmd )
     {
-    case XEN_DOMCTL_shadow_op:
-        return p2m_domctl(d, &domctl->u.shadow_op, u_domctl);
     case XEN_DOMCTL_cacheflush:
     {
         gfn_t s = _gfn(domctl->u.cacheflush.start_pfn);
diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h
index c8f14d13c2..91df922e1c 100644
--- a/xen/arch/arm/include/asm/p2m.h
+++ b/xen/arch/arm/include/asm/p2m.h
@@ -222,7 +222,6 @@ void p2m_restore_state(struct vcpu *n);
 /* Print debugging/statistial info about a domain's p2m */
 void p2m_dump_info(struct domain *d);
 
-unsigned int p2m_get_allocation(struct domain *d);
 int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted);
 int p2m_teardown_allocation(struct domain *d);
 
diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 8c1972e582..b2f7e8d804 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -92,14 +92,6 @@ static void p2m_free_page(struct domain *d, struct page_info *pg)
     spin_unlock(&d->arch.paging.lock);
 }
 
-/* Return the size of the pool, rounded up to the nearest MB */
-unsigned int p2m_get_allocation(struct domain *d)
-{
-    unsigned long nr_pages = ACCESS_ONCE(d->arch.paging.p2m_total_pages);
-
-    return ROUNDUP(nr_pages, 1 << (20 - PAGE_SHIFT)) >> (20 - PAGE_SHIFT);
-}
-
 /* Return the size of the pool, in bytes. */
 int arch_get_paging_mempool_size(struct domain *d, uint64_t *size)
 {
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:11:45 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:11:45 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447728.704281 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5w-00062R-5c; Wed, 23 Nov 2022 20:11:44 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447728.704281; Wed, 23 Nov 2022 20:11:44 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw5w-00062J-2g; Wed, 23 Nov 2022 20:11:44 +0000
Received: by outflank-mailman (input) for mailman id 447728;
 Wed, 23 Nov 2022 20:11:42 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5u-00061q-UD
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:42 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5u-0006ji-TR
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:42 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw5u-00086K-SX
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:42 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=s2irWC/HzxSXaD1uvu6jwKC1peeAXB/ZyJpJQI7CFcc=; b=Xv7I7r7JwjtTGPMmH+OjxoX226
	8jIaT4AKXJDarQ+ZFMpmHN6nIS4UYDBeN8/BZuq7ZMS1IBsy9m5sGwdF/CAAVnkdPlcK9gQbVC3gP
	TDM+Qc8asbLWEDZ0WENmfHxTARWUE6+V6vVVARuQiZVoIncNNtoNtxi6tXvkWzpZIXFQ=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen/arm: Correct the p2m pool size calculations
Message-Id: <E1oxw5u-00086K-SX@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:11:42 +0000

commit db8fa01c61db0317a9ee947925226234c65d48e8
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Thu Oct 20 12:14:30 2022 +0100
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Thu Nov 17 16:51:51 2022 +0000

    xen/arm: Correct the p2m pool size calculations
    
    Allocating or freeing p2m pages doesn't alter the size of the mempool; only
    the split between free and used pages.
    
    Right now, the hypercalls operate on the free subset of the pool, meaning that
    XEN_DOMCTL_get_paging_mempool_size varies with time as the guest shuffles its
    physmap, and XEN_DOMCTL_set_paging_mempool_size ignores the used subset of the
    pool and lets the guest grow unbounded.
    
    This fixes test-pagign-mempool on ARM so that the behaviour matches x86.
    
    This is part of XSA-409 / CVE-2022-33747.
    
    Fixes: cbea5a1149ca ("xen/arm: Allocate and free P2M pages from the P2M pool")
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Julien Grall <jgrall@amazon.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/arch/arm/p2m.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index b2f7e8d804..9bc5443d9e 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -72,7 +72,6 @@ static struct page_info *p2m_alloc_page(struct domain *d)
             spin_unlock(&d->arch.paging.lock);
             return NULL;
         }
-        d->arch.paging.p2m_total_pages--;
     }
     spin_unlock(&d->arch.paging.lock);
 
@@ -85,10 +84,7 @@ static void p2m_free_page(struct domain *d, struct page_info *pg)
     if ( is_hardware_domain(d) )
         free_domheap_page(pg);
     else
-    {
-        d->arch.paging.p2m_total_pages++;
         page_list_add_tail(pg, &d->arch.paging.p2m_freelist);
-    }
     spin_unlock(&d->arch.paging.lock);
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:11:54 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:11:54 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447729.704285 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw66-000657-6z; Wed, 23 Nov 2022 20:11:54 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447729.704285; Wed, 23 Nov 2022 20:11:54 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw66-00064z-4H; Wed, 23 Nov 2022 20:11:54 +0000
Received: by outflank-mailman (input) for mailman id 447729;
 Wed, 23 Nov 2022 20:11:53 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw65-00064s-0v
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:53 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw65-0006jv-0E
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:53 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw64-00086p-VR
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:11:52 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=UGVDdaezocIVY/3UGfIDMPHITjpsxptV2eRr/1YVXys=; b=e/6wqmApCDT+H4XA6spAl3sUfF
	faxnu618QI4mDCgATjgnnBLx+V1p/LQ7r7RPT0povCk248d4GgnG0ldTm9mRo9ant0h81kzHTJki6
	1Gz9/M4AL3HEPxpFoK/xZGvCY34bKJzmq9J4NNK6q9olZmT9qGPi24PGHDIBlFXKXsmU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] efifb: ignore frame buffer with invalid configuration
Message-Id: <E1oxw64-00086p-VR@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:11:52 +0000

commit 57f07cca82521088cca0c1fc36d6ffd06cb7de80
Author:     Roger Pau Monné <roger.pau@citrix.com>
AuthorDate: Mon Nov 21 12:21:51 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Nov 21 12:21:51 2022 +0100

    efifb: ignore frame buffer with invalid configuration
    
    On one of my boxes when the HDMI cable is not plugged in the
    FrameBufferBase of the EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE structure is
    set to 0 by the firmware (while some of the other fields looking
    plausible).
    
    Such (bogus address) ends up mapped in vesa_init(), and since it
    overlaps with a RAM region the whole system goes down pretty badly,
    see:
    
    (XEN) vesafb: framebuffer at 0x0000000000000000, mapped to 0xffff82c000201000, using 35209k, total 35209k
    (XEN) vesafb: mode is 0x37557x32, linelength=960, font 8x16
    (XEN) vesafb: Truecolor: size=8:8:8:8, shift=24:0:8:16
    (XEN) (XEN) (XEN) (XEN) (XEN) (XEN) (XEN) (XEN) �ERROR: Class:0; Subclass:0; Operation: 0
    ERROR: No ConOut
    ERROR: No ConIn
    
    Do like Linux and prevent using the EFI Frame Buffer if the base
    address is 0.  This is inline with the logic in Linuxes
    fb_base_is_valid() function at drivers/video/fbdev/efifb.c v6.0.9.
    
    See also Linux commit 133bb070e94ab41d750c6f2160c8843e46f11b78 for
    further reference.
    
    Also prevent using Frame Buffers that have a 0 height or width, as
    those are also invalid.
    
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 xen/arch/x86/efi/efi-boot.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h
index e82ac9daa7..27f928ed3c 100644
--- a/xen/arch/x86/efi/efi-boot.h
+++ b/xen/arch/x86/efi/efi-boot.h
@@ -506,6 +506,13 @@ static void __init efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop,
 #ifdef CONFIG_VIDEO
     int bpp = 0;
 
+    if ( !gop->Mode->FrameBufferBase || !mode_info->HorizontalResolution ||
+         !mode_info->VerticalResolution )
+    {
+        PrintErr(L"Invalid Frame Buffer configuration found\r\n");
+        return;
+    }
+
     switch ( mode_info->PixelFormat )
     {
     case PixelRedGreenBlueReserved8BitPerColor:
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:12:04 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:12:04 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447730.704289 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw6G-00067S-8b; Wed, 23 Nov 2022 20:12:04 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447730.704289; Wed, 23 Nov 2022 20:12:04 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw6G-00067L-5o; Wed, 23 Nov 2022 20:12:04 +0000
Received: by outflank-mailman (input) for mailman id 447730;
 Wed, 23 Nov 2022 20:12:03 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6F-00067E-3u
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:03 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6F-0006kI-3C
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:03 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6F-00087T-2F
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:03 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=ozdKVyFBXfmEhwJdjEMtnoM+UzIKx4d+onQmVdhGt4M=; b=uNmjDCz1xNL60bvj7zj3ADEPF8
	QYt165fhwYc6MlcbEpyzBM9TEB5/JyL0tJujB7Erh0nlW+qKd/s4PHTf/0IL0eLTpiS74wNfaT1lH
	CLZpJALQCo9ET8OoXM14I8NAmKWYeuG9h7Eu6TSrrXY4//nAvimuNvmwIAq99SORuLKA=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] libs/light: Propagate libxl__arch_domain_create() return code
Message-Id: <E1oxw6F-00087T-2F@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:12:03 +0000

commit 8cdfbf95b19c01fbb741c41d5ea5a94f8823964c
Author:     Anthony PERARD <anthony.perard@citrix.com>
AuthorDate: Mon Nov 21 12:23:01 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Nov 21 12:23:01 2022 +0100

    libs/light: Propagate libxl__arch_domain_create() return code
    
    Commit 34990446ca91 started to overwrite the `rc` value from
    libxl__arch_domain_create(), thus error aren't propagated anymore.
    
    Check `rc` value before doing the next thing.
    
    Fixes: 34990446ca91 ("libxl: don't ignore the return value from xc_cpuid_apply_policy")
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
    Reviewed-by: Jason Andryuk <jandryuk@gmail.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/libs/light/libxl_dom.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/libs/light/libxl_dom.c b/tools/libs/light/libxl_dom.c
index b59bbe00bb..fa5c79e4f6 100644
--- a/tools/libs/light/libxl_dom.c
+++ b/tools/libs/light/libxl_dom.c
@@ -377,6 +377,7 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid,
     state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->console_domid);
 
     rc = libxl__arch_domain_create(gc, d_config, state, domid);
+    if (rc) goto out;
 
     /* Construct a CPUID policy, but only for brand new domains.  Domains
      * being migrated-in/restored have CPUID handled during the
@@ -384,6 +385,7 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid,
     if (!state->restore)
         rc = libxl__cpuid_legacy(ctx, domid, false, info);
 
+out:
     return rc;
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:12:14 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:12:14 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447731.704293 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw6Q-0006AO-A7; Wed, 23 Nov 2022 20:12:14 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447731.704293; Wed, 23 Nov 2022 20:12:14 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw6Q-0006AG-7P; Wed, 23 Nov 2022 20:12:14 +0000
Received: by outflank-mailman (input) for mailman id 447731;
 Wed, 23 Nov 2022 20:12:13 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6P-0006A4-76
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:13 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6P-0006kS-6M
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:13 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6P-00089R-5Q
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:13 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=tVmYU7a5p6CCc9YY3AZut8FfbZk/LowVwNIxgs81qWs=; b=tsdqv1tWm7v8UJPxG3ccUddPwK
	KIDSWEB+ku6SlLUm+fBxENm+AJ3097dp64SYhH9xz2v1tK0Wtq9LtZxPo1PXolZO+8Oz+ErytN2ql
	Wpx+Qk+HjAX24FX0Li7uPycYZNN7Zn8GuIguHwZGzzXD631kGpRWNedU89wdeSp2RlwU=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] tools/libxl: Fixes to libxl__domain_set_paging_mempool_size()
Message-Id: <E1oxw6P-00089R-5Q@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:12:13 +0000

commit 8746d3e2550b142cd751ca7a041a38789a020d2b
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Fri Nov 18 16:53:45 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Mon Nov 21 16:12:41 2022 +0000

    tools/libxl: Fixes to libxl__domain_set_paging_mempool_size()
    
    The error message accidentally printed the bytes value as if it were kB.
    
    Furthermore, both b_info.shadow_memkb and shadow_mem are uint64_t, meaning
    there is a risk of overflow if the user specified a stupidly large value in
    the vm.cfg file.  Check and reject such a condition.
    
    Fixes: 7c3bbd940dd8 ("xen/arm, libxl: Revert XEN_DOMCTL_shadow_op; use p2m mempool hypercalls")
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/libs/light/libxl_dom.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/libs/light/libxl_dom.c b/tools/libs/light/libxl_dom.c
index fa5c79e4f6..b454f988fb 100644
--- a/tools/libs/light/libxl_dom.c
+++ b/tools/libs/light/libxl_dom.c
@@ -1458,10 +1458,18 @@ int libxl__domain_set_paging_mempool_size(
     shadow_mem = d_config->b_info.shadow_memkb;
     shadow_mem <<= 10;
 
+    if ((shadow_mem >> 10) != d_config->b_info.shadow_memkb) {
+        LOGED(ERROR, domid,
+              "shadow_memkb value %"PRIu64"kB too large",
+              d_config->b_info.shadow_memkb);
+        return ERROR_FAIL;
+    }
+
     int r = xc_set_paging_mempool_size(CTX->xch, domid, shadow_mem);
     if (r) {
         LOGED(ERROR, domid,
-              "Failed to set paging mempool size to %"PRIu64"kB", shadow_mem);
+              "Failed to set paging mempool size to %"PRIu64"kB",
+              d_config->b_info.shadow_memkb);
         return ERROR_FAIL;
     }
 
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Wed Nov 23 20:12:24 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 23 Nov 2022 20:12:24 +0000
Received: from list by lists.xenproject.org with outflank-mailman.447732.704297 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw6a-0006E9-BU; Wed, 23 Nov 2022 20:12:24 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 447732.704297; Wed, 23 Nov 2022 20:12:24 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1oxw6a-0006E2-8v; Wed, 23 Nov 2022 20:12:24 +0000
Received: by outflank-mailman (input) for mailman id 447732;
 Wed, 23 Nov 2022 20:12:23 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6Z-0006Dd-A3
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:23 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6Z-0006ks-9I
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:23 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1oxw6Z-00089q-8U
 for xen-changelog@lists.xenproject.org; Wed, 23 Nov 2022 20:12:23 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=nLDK8cxtFOmjzyCdm68nhNKTgBYXhs27r3AyjDn07tw=; b=qHJVyT4Pl6LiZ/ark/Qir9mMzO
	KOPwkb9QNURhioXmCS5umrK21Gr8ZVePA7oGN9XaIY+CYnLVejNOg37a26OrgNy98QIKtoqzQo6hv
	fvTBae0WmlqLX6/WAUvqivJvqWJ4FCe3yzwP2bMcOac/Gmc9Z0fTDJJXrJcnM/NFgLu0=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen master] xen/flask: Wire up XEN_DOMCTL_{get,set}_paging_mempool_size
Message-Id: <E1oxw6Z-00089q-8U@xenbits.xenproject.org>
Date: Wed, 23 Nov 2022 20:12:23 +0000

commit 345135942bf9632eba1409ba432cfcae3b7649c7
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Mon Nov 21 12:46:39 2022 +0000
Commit:     Andrew Cooper <andrew.cooper3@citrix.com>
CommitDate: Mon Nov 21 16:12:41 2022 +0000

    xen/flask: Wire up XEN_DOMCTL_{get,set}_paging_mempool_size
    
    These were overlooked in the original patch, and noticed by OSSTest which does
    run some Flask tests.
    
    Fixes: 22b20bd98c02 ("xen: Introduce non-broken hypercalls for the paging mempool size")
    Suggested-by: Daniel Smith <dpsmith@apertussolutions.com>
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Reviewed-by: Jason Andryuk <jandryuk@gmail.com>
    Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
    Release-acked-by: Henry Wang <Henry.Wang@arm.com>
---
 tools/flask/policy/modules/dom0.te  | 3 ++-
 tools/flask/policy/modules/xen.if   | 5 +++--
 xen/xsm/flask/hooks.c               | 6 ++++++
 xen/xsm/flask/policy/access_vectors | 4 ++++
 4 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/tools/flask/policy/modules/dom0.te b/tools/flask/policy/modules/dom0.te
index f710ff9941..f1dcff48e2 100644
--- a/tools/flask/policy/modules/dom0.te
+++ b/tools/flask/policy/modules/dom0.te
@@ -35,7 +35,8 @@ allow dom0_t dom0_t:domain {
 	setvcpucontext max_vcpus setaffinity getaffinity getscheduler
 	getdomaininfo getvcpuinfo getvcpucontext setdomainmaxmem setdomainhandle
 	setdebugging hypercall settime setaddrsize getaddrsize trigger
-	getpodtarget setpodtarget set_misc_info set_virq_handler
+	getpodtarget setpodtarget getpagingmempool setpagingmempool set_misc_info
+	set_virq_handler
 };
 allow dom0_t dom0_t:domain2 {
 	set_cpu_policy gettsc settsc setscheduler set_vnumainfo
diff --git a/tools/flask/policy/modules/xen.if b/tools/flask/policy/modules/xen.if
index 424daab6a0..11c1562aa5 100644
--- a/tools/flask/policy/modules/xen.if
+++ b/tools/flask/policy/modules/xen.if
@@ -49,7 +49,8 @@ define(`create_domain_common', `
 	allow $1 $2:domain { create max_vcpus setdomainmaxmem setaddrsize
 			getdomaininfo hypercall setvcpucontext getscheduler
 			getvcpuinfo getaddrsize getaffinity setaffinity
-			settime setdomainhandle getvcpucontext set_misc_info };
+			settime setdomainhandle getvcpucontext set_misc_info
+			getpagingmempool setpagingmempool };
 	allow $1 $2:domain2 { set_cpu_policy settsc setscheduler setclaim
 			set_vnumainfo get_vnumainfo cacheflush
 			psr_cmt_op psr_alloc soft_reset
@@ -92,7 +93,7 @@ define(`manage_domain', `
 	allow $1 $2:domain { getdomaininfo getvcpuinfo getaffinity
 			getaddrsize pause unpause trigger shutdown destroy
 			setaffinity setdomainmaxmem getscheduler resume
-			setpodtarget getpodtarget };
+			setpodtarget getpodtarget getpagingmempool setpagingmempool };
     allow $1 $2:domain2 set_vnumainfo;
 ')
 
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index 391aec4dc2..78225f68c1 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -822,6 +822,12 @@ static int cf_check flask_domctl(struct domain *d, int cmd)
     case XEN_DOMCTL_get_cpu_policy:
         return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__GET_CPU_POLICY);
 
+    case XEN_DOMCTL_get_paging_mempool_size:
+        return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETPAGINGMEMPOOL);
+
+    case XEN_DOMCTL_set_paging_mempool_size:
+        return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETPAGINGMEMPOOL);
+
     default:
         return avc_unknown_permission("domctl", cmd);
     }
diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors
index 6359c7fc87..4e6710a63e 100644
--- a/xen/xsm/flask/policy/access_vectors
+++ b/xen/xsm/flask/policy/access_vectors
@@ -180,6 +180,10 @@ class domain
     set_misc_info
 # XEN_DOMCTL_set_virq_handler
     set_virq_handler
+# XEN_DOMCTL_get_paging_mempool_size
+    getpagingmempool
+# XEN_DOMCTL_set_paging_mempool_size
+    setpagingmempool
 }
 
 # This is a continuation of class domain, since only 32 permissions can be
--
generated by git-patchbot for /home/xen/git/xen.git#master


From xen-changelog-bounces@lists.xenproject.org Mon Nov 28 18:55:08 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Mon, 28 Nov 2022 18:55:08 +0000
Received: from list by lists.xenproject.org with outflank-mailman.449128.705774 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ozjHT-0006zA-6Y; Mon, 28 Nov 2022 18:55:03 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 449128.705774; Mon, 28 Nov 2022 18:55:03 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ozjHT-0006z2-2S; Mon, 28 Nov 2022 18:55:03 +0000
Received: by outflank-mailman (input) for mailman id 449128;
 Mon, 28 Nov 2022 18:55:02 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHS-0006yw-A1
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:02 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHS-0007Xf-8E
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:02 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHS-0006O7-73
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:02 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=m3FJB04tbZYGq+8w7RwyoD3C96EFGAxCSybh6YUwwis=; b=VJgkfqqpX1iQ0JswPsyrmQOv1t
	scFULWGR47Ldg/9NQYM47929V3OyShWhRRKLSpMZtuxuVT0ay7RoGLbIFj9F8iQ2XrASQVfSOtUIm
	F89HyjQGGjzKe9RmQ58Qqe3sQdNh04lbyXPimzKl9gxd9cHjrP1R2WYVgFSnrMGPYong=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] x86/spec-ctrl: Fill in whitepaper URL
Message-Id: <E1ozjHS-0006O7-73@xenbits.xenproject.org>
Date: Mon, 28 Nov 2022 18:55:02 +0000

commit 43a5ce211ba55a34579519066c1be939549db319
Author:     Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Mon Nov 28 11:45:21 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Nov 28 11:45:21 2022 +0100

    x86/spec-ctrl: Fill in whitepaper URL
    
    ... now that we a link available.
    
    Fixes: 9deaf2d932f0 ("x86/spec-ctrl: Enable Zen2 chickenbit")
    Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Acked-by: Jan Beulich <jbeulich@suse.com>
    master commit: 764146ed8a7a44034c3efe658333993ca250d69a
    master date: 2022-11-16 12:54:08 +0000
---
 xen/arch/x86/cpu/amd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index 9635eee619..08e3e1e8a2 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -735,7 +735,7 @@ void amd_init_ssbd(const struct cpuinfo_x86 *c)
  * On Zen2 we offer this chicken (bit) on the altar of Speculation.
  *
  * Refer to the AMD Branch Type Confusion whitepaper:
- * https://XXX
+ * https://www.amd.com/system/files/documents/technical-guidance-for-mitigating-branch-type-confusion.pdf
  *
  * Setting this unnamed bit supposedly causes prediction information on
  * non-branch instructions to be ignored.  It is to be set unilaterally in
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Mon Nov 28 18:55:13 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Mon, 28 Nov 2022 18:55:13 +0000
Received: from list by lists.xenproject.org with outflank-mailman.449129.705777 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ozjHd-00072I-6r; Mon, 28 Nov 2022 18:55:13 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 449129.705777; Mon, 28 Nov 2022 18:55:13 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ozjHd-00072A-46; Mon, 28 Nov 2022 18:55:13 +0000
Received: by outflank-mailman (input) for mailman id 449129;
 Mon, 28 Nov 2022 18:55:12 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHc-00071W-CN
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:12 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHc-0007Xp-BY
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:12 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHc-0006Ob-AN
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:12 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=bTUNu10lDQgFTlO8eIEWaNA5oL40y7tTZszIRy88rKA=; b=s/DHVq7BJvhAKkmwKIC6B9WCK5
	cmc41UsrUeE/xbO6Yq/8tyuX2G1bzBO1tyW8TmWy/xUL2zkcwMCNTsSU22rrTBSY2xK6Lzu6sb3fl
	3KMZZwuqXWgMGziPF7pQnj2bSIl0GxMvetypBGQxuULkjGdKPlVbLjdCBLlU3Y0UKVZ8=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] efifb: ignore frame buffer with invalid configuration
Message-Id: <E1ozjHc-0006Ob-AN@xenbits.xenproject.org>
Date: Mon, 28 Nov 2022 18:55:12 +0000

commit 4759d80fd291b144069a9705118fdee19bed9595
Author:     Roger Pau Monné <roger.pau@citrix.com>
AuthorDate: Mon Nov 28 11:45:45 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Nov 28 11:45:45 2022 +0100

    efifb: ignore frame buffer with invalid configuration
    
    On one of my boxes when the HDMI cable is not plugged in the
    FrameBufferBase of the EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE structure is
    set to 0 by the firmware (while some of the other fields looking
    plausible).
    
    Such (bogus address) ends up mapped in vesa_init(), and since it
    overlaps with a RAM region the whole system goes down pretty badly,
    see:
    
    (XEN) vesafb: framebuffer at 0x0000000000000000, mapped to 0xffff82c000201000, using 35209k, total 35209k
    (XEN) vesafb: mode is 0x37557x32, linelength=960, font 8x16
    (XEN) vesafb: Truecolor: size=8:8:8:8, shift=24:0:8:16
    (XEN) (XEN) (XEN) (XEN) (XEN) (XEN) (XEN) (XEN) �ERROR: Class:0; Subclass:0; Operation: 0
    ERROR: No ConOut
    ERROR: No ConIn
    
    Do like Linux and prevent using the EFI Frame Buffer if the base
    address is 0.  This is inline with the logic in Linuxes
    fb_base_is_valid() function at drivers/video/fbdev/efifb.c v6.0.9.
    
    See also Linux commit 133bb070e94ab41d750c6f2160c8843e46f11b78 for
    further reference.
    
    Also prevent using Frame Buffers that have a 0 height or width, as
    those are also invalid.
    
    Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
    Reviewed-by: Jan Beulich <jbeulich@suse.com>
    master commit: 57f07cca82521088cca0c1fc36d6ffd06cb7de80
    master date: 2022-11-21 12:21:51 +0100
---
 xen/arch/x86/efi/efi-boot.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h
index d996016223..01e63c0dd4 100644
--- a/xen/arch/x86/efi/efi-boot.h
+++ b/xen/arch/x86/efi/efi-boot.h
@@ -506,6 +506,13 @@ static void __init efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop,
 #ifdef CONFIG_VIDEO
     int bpp = 0;
 
+    if ( !gop->Mode->FrameBufferBase || !mode_info->HorizontalResolution ||
+         !mode_info->VerticalResolution )
+    {
+        PrintErr(L"Invalid Frame Buffer configuration found\r\n");
+        return;
+    }
+
     switch ( mode_info->PixelFormat )
     {
     case PixelRedGreenBlueReserved8BitPerColor:
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


From xen-changelog-bounces@lists.xenproject.org Mon Nov 28 18:55:23 2022
Return-path: <xen-changelog-bounces@lists.xenproject.org>
Envelope-to: archives@lists.xen.org
Delivery-date: Mon, 28 Nov 2022 18:55:23 +0000
Received: from list by lists.xenproject.org with outflank-mailman.449130.705781 (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ozjHn-00075P-8a; Mon, 28 Nov 2022 18:55:23 +0000
X-Outflank-Mailman: Message body and most headers restored to incoming version
Received: by outflank-mailman (output) from mailman id 449130.705781; Mon, 28 Nov 2022 18:55:23 +0000
Received: from localhost ([127.0.0.1] helo=lists.xenproject.org)
	by lists.xenproject.org with esmtp (Exim 4.92)
	(envelope-from <xen-changelog-bounces@lists.xenproject.org>)
	id 1ozjHn-00075H-5q; Mon, 28 Nov 2022 18:55:23 +0000
Received: by outflank-mailman (input) for mailman id 449130;
 Mon, 28 Nov 2022 18:55:22 +0000
Received: from mail.xenproject.org ([104.130.215.37])
 by lists.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHm-000757-Gt
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:22 +0000
Received: from xenbits.xenproject.org ([104.239.192.120])
 by mail.xenproject.org with esmtp (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHm-0007YC-FG
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:22 +0000
Received: from xen by xenbits.xenproject.org with local (Exim 4.92)
 (envelope-from <ian.jackson@eu.citrix.com>) id 1ozjHm-0006P0-Dl
 for xen-changelog@lists.xenproject.org; Mon, 28 Nov 2022 18:55:22 +0000
X-BeenThere: xen-changelog@lists.xenproject.org
List-Id: "Change log for Mercurial \(receive only\)"
 <xen-changelog.lists.xenproject.org>
List-Unsubscribe: <https://lists.xenproject.org/mailman/options/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=unsubscribe>
List-Post: <mailto:xen-changelog@lists.xenproject.org>
List-Help: <mailto:xen-changelog-request@lists.xenproject.org?subject=help>
List-Subscribe: <https://lists.xenproject.org/mailman/listinfo/xen-changelog>, 
 <mailto:xen-changelog-request@lists.xenproject.org?subject=subscribe>
Errors-To: xen-changelog-bounces@lists.xenproject.org
Precedence: list
Sender: "Xen-changelog" <xen-changelog-bounces@lists.xenproject.org>
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org;
	s=20200302mail; h=Date:Message-Id:Subject:Reply-To:To:From;
	bh=cUIl9n7C4YIFy0Y3c5Kfo9Amixlbnust0BSurB+nmOk=; b=c36jgtjfthCF1cVDeeCfXXY2fv
	q1OZ0gIRT9NqL8z3pOHibA1+g++AAwrswcVe6Y3won4UwYRnmYp12X9ojl47bVTM7oHnnaV9flwNL
	3EY0TeADaAQZlelgfwJ304GI9OKdmFya6j9Prbsy/vWjGn5qJTBajWT/zNqnJSZLwnEM=;
From: patchbot@xen.org
To: xen-changelog@lists.xenproject.org
Reply-To: xen-devel@lists.xenproject.org
Subject: [xen stable-4.16] libs/light: Propagate libxl__arch_domain_create() return code
Message-Id: <E1ozjHm-0006P0-Dl@xenbits.xenproject.org>
Date: Mon, 28 Nov 2022 18:55:22 +0000

commit 4320b31106efe4cf78867e1da379f7534e1c5c34
Author:     Anthony PERARD <anthony.perard@citrix.com>
AuthorDate: Mon Nov 28 11:46:53 2022 +0100
Commit:     Jan Beulich <jbeulich@suse.com>
CommitDate: Mon Nov 28 11:46:53 2022 +0100

    libs/light: Propagate libxl__arch_domain_create() return code
    
    Commit 34990446ca91 started to overwrite the `rc` value from
    libxl__arch_domain_create(), thus error aren't propagated anymore.
    
    Check `rc` value before doing the next thing.
    
    Fixes: 34990446ca91 ("libxl: don't ignore the return value from xc_cpuid_apply_policy")
    Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
    Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
    Reviewed-by: Jason Andryuk <jandryuk@gmail.com>
    master commit: 8cdfbf95b19c01fbb741c41d5ea5a94f8823964c
    master date: 2022-11-21 12:23:01 +0100
---
 tools/libs/light/libxl_dom.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/libs/light/libxl_dom.c b/tools/libs/light/libxl_dom.c
index fe9f760f71..73fccd9243 100644
--- a/tools/libs/light/libxl_dom.c
+++ b/tools/libs/light/libxl_dom.c
@@ -379,6 +379,7 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid,
     state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->console_domid);
 
     rc = libxl__arch_domain_create(gc, d_config, state, domid);
+    if (rc) goto out;
 
     /* Construct a CPUID policy, but only for brand new domains.  Domains
      * being migrated-in/restored have CPUID handled during the
@@ -386,6 +387,7 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid,
     if (!state->restore)
         rc = libxl__cpuid_legacy(ctx, domid, false, info);
 
+out:
     return rc;
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.16


