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)
This commit is contained in:
Bojan Novković 2024-09-29 13:10:10 +02:00 committed by Ed Maste
parent 2403e6d5aa
commit 2dea4de8e0

View file

@ -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);
}