Index: head/sys/amd64/include/vmm.h =================================================================== --- head/sys/amd64/include/vmm.h +++ head/sys/amd64/include/vmm.h @@ -114,9 +114,30 @@ #define VM_INTINFO_HWEXCEPTION (3 << 8) #define VM_INTINFO_SWINTR (4 << 8) -#ifdef _KERNEL +/* + * The VM name has to fit into the pathname length constraints of devfs, + * governed primarily by SPECNAMELEN. The length is the total number of + * characters in the full path, relative to the mount point and not + * including any leading '/' characters. + * A prefix and a suffix are added to the name specified by the user. + * The prefix is usually "vmm/" or "vmm.io/", but can be a few characters + * longer for future use. + * The suffix is a string that identifies a bootrom image or some similar + * image that is attached to the VM. A separator character gets added to + * the suffix automatically when generating the full path, so it must be + * accounted for, reducing the effective length by 1. + * The effective length of a VM name is 229 bytes for FreeBSD 13 and 37 + * bytes for FreeBSD 12. A minimum length is set for safety and supports + * a SPECNAMELEN as small as 32 on old systems. + */ +#define VM_MAX_PREFIXLEN 10 +#define VM_MAX_SUFFIXLEN 15 +#define VM_MIN_NAMELEN 6 +#define VM_MAX_NAMELEN \ + (SPECNAMELEN - VM_MAX_PREFIXLEN - VM_MAX_SUFFIXLEN - 1) -#define VM_MAX_NAMELEN 32 +#ifdef _KERNEL +CTASSERT(VM_MAX_NAMELEN >= VM_MIN_NAMELEN); struct vm; struct vm_exception; Index: head/sys/amd64/include/vmm_dev.h =================================================================== --- head/sys/amd64/include/vmm_dev.h +++ head/sys/amd64/include/vmm_dev.h @@ -51,7 +51,7 @@ struct vm_memseg { int segid; size_t len; - char name[SPECNAMELEN + 1]; + char name[VM_MAX_SUFFIXLEN + 1]; }; struct vm_register { Index: head/sys/amd64/vmm/vmm_dev.c =================================================================== --- head/sys/amd64/vmm/vmm_dev.c +++ head/sys/amd64/vmm/vmm_dev.c @@ -245,7 +245,7 @@ return (error); } -CTASSERT(sizeof(((struct vm_memseg *)0)->name) >= SPECNAMELEN + 1); +CTASSERT(sizeof(((struct vm_memseg *)0)->name) >= VM_MAX_SUFFIXLEN + 1); static int get_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg) @@ -265,7 +265,8 @@ } KASSERT(dsc != NULL, ("%s: devmem segment %d not found", __func__, mseg->segid)); - error = copystr(dsc->name, mseg->name, SPECNAMELEN + 1, NULL); + error = copystr(dsc->name, mseg->name, sizeof(mseg->name), + NULL); } else { bzero(mseg->name, sizeof(mseg->name)); } @@ -284,10 +285,14 @@ name = NULL; sysmem = true; + /* + * The allocation is lengthened by 1 to hold a terminating NUL. It'll + * by stripped off when devfs processes the full string. + */ if (VM_MEMSEG_NAME(mseg)) { sysmem = false; - name = malloc(SPECNAMELEN + 1, M_VMMDEV, M_WAITOK); - error = copystr(mseg->name, name, SPECNAMELEN + 1, 0); + name = malloc(sizeof(mseg->name) M_VMMDEV, M_WAITOK); + error = copystr(mseg->name, name, sizeof(mseg->name), NULL); if (error) goto done; } @@ -894,26 +899,29 @@ static int sysctl_vmm_destroy(SYSCTL_HANDLER_ARGS) { - int error; - char buf[VM_MAX_NAMELEN]; struct devmem_softc *dsc; struct vmmdev_softc *sc; struct cdev *cdev; + char *buf; + int error, buflen; error = vmm_priv_check(req->td->td_ucred); if (error) return (error); - strlcpy(buf, "beavis", sizeof(buf)); - error = sysctl_handle_string(oidp, buf, sizeof(buf), req); + buflen = VM_MAX_NAMELEN + 1; + buf = malloc(buflen, M_VMMDEV, M_WAITOK | M_ZERO); + strlcpy(buf, "beavis", buflen); + error = sysctl_handle_string(oidp, buf, buflen, req); if (error != 0 || req->newptr == NULL) - return (error); + goto out; mtx_lock(&vmmdev_mtx); sc = vmmdev_lookup(buf); if (sc == NULL || sc->cdev == NULL) { mtx_unlock(&vmmdev_mtx); - return (EINVAL); + error = EINVAL; + goto out; } /* @@ -943,7 +951,11 @@ destroy_dev_sched_cb(dsc->cdev, devmem_destroy, dsc); } destroy_dev_sched_cb(cdev, vmmdev_destroy, sc); - return (0); + error = 0; + +out: + free(buf, M_VMMDEV); + return (error); } SYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON, @@ -961,30 +973,34 @@ static int sysctl_vmm_create(SYSCTL_HANDLER_ARGS) { - int error; struct vm *vm; struct cdev *cdev; struct vmmdev_softc *sc, *sc2; - char buf[VM_MAX_NAMELEN]; + char *buf; + int error, buflen; error = vmm_priv_check(req->td->td_ucred); if (error) return (error); - strlcpy(buf, "beavis", sizeof(buf)); - error = sysctl_handle_string(oidp, buf, sizeof(buf), req); + buflen = VM_MAX_NAMELEN + 1; + buf = malloc(buflen, M_VMMDEV, M_WAITOK | M_ZERO); + strlcpy(buf, "beavis", buflen); + error = sysctl_handle_string(oidp, buf, buflen, req); if (error != 0 || req->newptr == NULL) - return (error); + goto out; mtx_lock(&vmmdev_mtx); sc = vmmdev_lookup(buf); mtx_unlock(&vmmdev_mtx); - if (sc != NULL) - return (EEXIST); + if (sc != NULL) { + error = EEXIST; + goto out; + } error = vm_create(buf, &vm); if (error != 0) - return (error); + goto out; sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO); sc->vm = vm; @@ -1004,14 +1020,15 @@ if (sc2 != NULL) { vmmdev_destroy(sc); - return (EEXIST); + error = EEXIST; + goto out; } error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, NULL, UID_ROOT, GID_WHEEL, 0600, "vmm/%s", buf); if (error != 0) { vmmdev_destroy(sc); - return (error); + goto out; } mtx_lock(&vmmdev_mtx); @@ -1019,7 +1036,9 @@ sc->cdev->si_drv1 = sc; mtx_unlock(&vmmdev_mtx); - return (0); +out: + free(buf, M_VMMDEV); + return (error); } SYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON,