aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2023-08-17 18:49:54 +0000
committerMark Johnston <markj@FreeBSD.org>2023-08-24 13:33:11 +0000
commit7756dcc46f3b1059e68fdd0099ca26618d5d8d62 (patch)
tree83b37b449c68a80dcb74ec9caf847cf10bab3ac8
parenta4db69370ed526e3d840e1b7ef223ba8dc403d18 (diff)
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
-rw-r--r--sys/amd64/vmm/vmm_dev.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
index 70434a44e5f4..46faccf9b7e3 100644
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -878,11 +878,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)
@@ -891,6 +892,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);