git: 2dea4de8e0f0 - stable/14 - vmm: Properly handle writes spanning across two pages in vm_handle_db

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Sun, 06 Oct 2024 15:01:45 UTC
The branch stable/14 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=2dea4de8e0f0ee886cf46a5ceddabd4192843445

commit 2dea4de8e0f0ee886cf46a5ceddabd4192843445
Author:     Bojan Novković <bnovkov@FreeBSD.org>
AuthorDate: 2024-09-29 11:10:10 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2024-10-06 15:01:24 +0000

    vmm: Properly handle writes spanning across two pages in vm_handle_db
    
    The vm_handle_db function is responsible for writing correct status
    register values into memory when a guest VM is being single-stepped
    using the RFLAGS.TF mechanism. However, it currently does not properly
    handle an edge case where the resulting write spans across two pages.
    This commit fixes this by making vm_handle_db use two vm_copy_info
    structs.
    
    Security:       HYP-09
    Reviewed by:    markj
    
    (cherry picked from commit 51fda658baa3f80c9778f3a9873fbf67df87119b)
---
 sys/amd64/vmm/vmm.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index f399f876717d..ef4c7a9af2ea 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -1771,7 +1771,7 @@ vm_handle_db(struct vcpu *vcpu, struct vm_exit *vme, bool *retu)
 	int error, fault;
 	uint64_t rsp;
 	uint64_t rflags;
-	struct vm_copyinfo copyinfo;
+	struct vm_copyinfo copyinfo[2];
 
 	*retu = true;
 	if (!vme->u.dbg.pushf_intercept || vme->u.dbg.tf_shadow_val != 0) {
@@ -1780,21 +1780,21 @@ vm_handle_db(struct vcpu *vcpu, struct vm_exit *vme, bool *retu)
 
 	vm_get_register(vcpu, VM_REG_GUEST_RSP, &rsp);
 	error = vm_copy_setup(vcpu, &vme->u.dbg.paging, rsp, sizeof(uint64_t),
-	    VM_PROT_RW, &copyinfo, 1, &fault);
+	    VM_PROT_RW, copyinfo, nitems(copyinfo), &fault);
 	if (error != 0 || fault != 0) {
 		*retu = false;
 		return (EINVAL);
 	}
 
 	/* Read pushed rflags value from top of stack. */
-	vm_copyin(&copyinfo, &rflags, sizeof(uint64_t));
+	vm_copyin(copyinfo, &rflags, sizeof(uint64_t));
 
 	/* Clear TF bit. */
 	rflags &= ~(PSL_T);
 
 	/* Write updated value back to memory. */
-	vm_copyout(&rflags, &copyinfo, sizeof(uint64_t));
-	vm_copy_teardown(&copyinfo, 1);
+	vm_copyout(&rflags, copyinfo, sizeof(uint64_t));
+	vm_copy_teardown(copyinfo, nitems(copyinfo));
 
 	return (0);
 }