git: 5635d5b61e21 - main - vmm: Fix VM_GET_CPUS compatibility

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Thu, 17 Aug 2023 22:11:32 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=5635d5b61e2113b91db921267cb476b1fde93e9e

commit 5635d5b61e2113b91db921267cb476b1fde93e9e
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2023-08-17 18:49:54 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-08-17 22:10:02 +0000

    vmm: Fix VM_GET_CPUS compatibility
    
    bhyve in a 13.x jail fails to boot guests with more than one vCPU
    because they pass too small a buffer to VM_GET_CPUS, causing the ioctl
    handler to return ERANGE.  Handle this the same way as cpuset system
    calls: make sure that the result can fit in the truncated space, and
    relax the check on the cpuset buffer.
    
    As a side effect, fix an insufficient bounds check on "size".  The
    signed/unsigned comparison with sizeof(cpuset_t) fails to exclude
    negative values, so we can end up allocating impossibly large amounts of
    memory.
    
    Reviewed by:    jhb
    MFC after:      1 week
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D41496
---
 sys/amd64/vmm/vmm_dev.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
index c13adfd599ee..cae15d7059cb 100644
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -989,11 +989,12 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
 		error = 0;
 		vm_cpuset = (struct vm_cpuset *)data;
 		size = vm_cpuset->cpusetsize;
-		if (size < sizeof(cpuset_t) || size > CPU_MAXSIZE / NBBY) {
+		if (size < 1 || size > CPU_MAXSIZE / NBBY) {
 			error = ERANGE;
 			break;
 		}
-		cpuset = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
+		cpuset = malloc(max(size, sizeof(cpuset_t)), M_TEMP,
+		    M_WAITOK | M_ZERO);
 		if (vm_cpuset->which == VM_ACTIVE_CPUS)
 			*cpuset = vm_active_cpus(sc->vm);
 		else if (vm_cpuset->which == VM_SUSPENDED_CPUS)
@@ -1002,6 +1003,8 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
 			*cpuset = vm_debug_cpus(sc->vm);
 		else
 			error = EINVAL;
+		if (error == 0 && size < howmany(CPU_FLS(cpuset), NBBY))
+			error = ERANGE;
 		if (error == 0)
 			error = copyout(cpuset, vm_cpuset->cpus, size);
 		free(cpuset, M_TEMP);