On Mon, Oct 12, 2026 at 10:27:43PM +0200, Stefan Sperling wrote:
> On Mon, Oct 12, 2026 at 03:12:56PM -0500, izzy Meyer wrote:
> > vm debian Oct 12 15:09:13 Tower-OpenBaSeD vmd[38243]: config_setvm:
> > can't open /dev/tap4 Oct 12 15:09:13 Tower-OpenBaSeD vmd[38243]: failed
> > to start vm debian Oct 12 15:09:25 Tower-OpenBaSeD vmd[60481]: denied
> > request 3 from uid 1000 Oct 12 15:09:32 Tower-OpenBaSeD vmd[38243]:
> > config_setvm: can't open /dev/tap4 Oct 12 15:09:32 Tower-OpenBaSeD
> > vmd[38243]: failed to start vm debian
> >
> > This is weird as I only see 4 existing tap(4) devices in /dev:
> > ~ $ ls /dev/tap*
> > /dev/tap0 /dev/tap1 /dev/tap2 /dev/tap3
> >
> > Do I need to MAKEDEV more tap(4) devices to fix this? I'm too worried
> > I'll break something if I try
>
> Creating the missing tap devices with MAKEDEV is indeed the right thing
> to do here. There shouldn't be any problems caused by doing this.
>
> I wish vmd did report the filename it failed to open in the error message.
>
we'll need to send back the failing interface name to vmctl in order to
print it, since vmctl doesn't know what interface name is being used at
the time of vmctl start.
this diff "does the job" but after I made this I decided we should probably
not just provide "failed_ifname" but rather perhaps have vmd send back
a generic "why did the start fail" message. it might be due to missing
tapX, it might be due to missing firmware, missing disks, ENOMEM, etc. this
only handles the tapX case.
for now, OP can use this diff to alleviate the immediate issue but I
don't want to commit this as-is. needs more thought.
before:
-up- ~> vmctl start -c openbsd
vmctl: start vm command failed: No such file or directory
after:
-up- ~> vmctl start -c openbsd
vmctl: can't open /dev/tap99: No such file or directory
Index: usr.sbin/vmctl/vmctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/vmctl.c,v
diff -u -p -a -u -r1.99 vmctl.c
--- usr.sbin/vmctl/vmctl.c 18 Sep 2026 02:35:55 -0000 1.99
+++ usr.sbin/vmctl/vmctl.c 13 Oct 2026 08:43:39 -0000
@@ -265,7 +265,11 @@ vm_start_complete(struct imsg *imsg, int
break;
default:
errno = res;
- warn("start vm command failed");
+ if (vmr.vmr_ifname[0] != '\0')
+ warn("can't open /dev/%s",
+ vmr.vmr_ifname);
+ else
+ warn("start vm command failed");
*ret = EIO;
}
} else if (autoconnect) {
@@ -915,6 +919,7 @@ vmop_result_read(struct imsg *imsg, stru
fatal("%s", __func__);
vmr->vmr_ttyname[sizeof(vmr->vmr_ttyname) - 1] = '\0';
+ vmr->vmr_ifname[sizeof(vmr->vmr_ifname) - 1] = '\0';
}
void
Index: usr.sbin/vmd/config.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/config.c,v
diff -u -p -a -u -r1.84 config.c
--- usr.sbin/vmd/config.c 30 Aug 2026 23:23:18 -0000 1.84
+++ usr.sbin/vmd/config.c 13 Oct 2026 08:43:39 -0000
@@ -186,7 +186,8 @@ config_setreset(struct vmd *env, unsigne
* Returns 0 on success, error code on failure.
*/
int
-config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid)
+config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid,
+ char *failed_ifname)
{
int diskfds[VM_MAX_DISKS_PER_VM][VM_MAX_BASE_PER_DISK];
struct vmd_if *vif;
@@ -204,6 +205,9 @@ config_setvm(struct privsep *ps, struct
struct vmop_addr_req var;
size_t bytes = 0;
+ if (failed_ifname != NULL)
+ failed_ifname[0] = '\0';
+
if (vm->vm_state & VM_STATE_RUNNING) {
log_warnx("%s: vm is already running", __func__);
return (EALREADY);
@@ -428,6 +432,8 @@ config_setvm(struct privsep *ps, struct
}
if (tapfds[i] == -1) {
ret = errno;
+ if (failed_ifname != NULL)
+ strlcpy(failed_ifname, s, IF_NAMESIZE);
log_warnx("%s: can't open /dev/%s", __func__, s);
goto fail;
}
Index: usr.sbin/vmd/vm.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/vm.c,v
diff -u -p -a -u -r1.135 vm.c
--- usr.sbin/vmd/vm.c 19 Sep 2026 17:21:52 -0000 1.135
+++ usr.sbin/vmd/vm.c 13 Oct 2026 08:53:43 -0000
@@ -387,7 +387,7 @@ vm_dispatch_vmm(int fd, short event, voi
_exit(0);
break;
case IMSG_VMDOP_PAUSE_VM:
- vmr.vmr_result = 0;
+ memset(&vmr, 0, sizeof(vmr));
vmr.vmr_id = vm->vm_vmid;
pause_vm(vm);
imsg_compose_event(&vm->vm_iev,
@@ -395,7 +395,7 @@ vm_dispatch_vmm(int fd, short event, voi
sizeof(vmr));
break;
case IMSG_VMDOP_UNPAUSE_VM:
- vmr.vmr_result = 0;
+ memset(&vmr, 0, sizeof(vmr));
vmr.vmr_id = vm->vm_vmid;
unpause_vm(vm);
imsg_compose_event(&vm->vm_iev,
Index: usr.sbin/vmd/vmd.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/vmd.c,v
diff -u -p -a -u -r1.186 vmd.c
--- usr.sbin/vmd/vmd.c 5 Oct 2026 23:07:37 -0000 1.186
+++ usr.sbin/vmd/vmd.c 13 Oct 2026 08:43:39 -0000
@@ -99,6 +99,7 @@ vmd_dispatch_control(int fd, struct priv
struct vmop_result vmr;
struct vmd_vm *vm = NULL;
char *str = NULL;
+ char failed_ifname[IF_NAMESIZE] = "";
uint32_t peer_id, type, vm_id = 0;
peer_id = imsg_get_id(imsg);
@@ -155,7 +156,7 @@ vmd_dispatch_control(int fd, struct priv
/* Try to start the launch of the VM. */
res = config_setvm(ps, vm, peer_id,
- vm->vm_params.vmc_owner.uid);
+ vm->vm_params.vmc_owner.uid, failed_ifname);
if (res) {
if (vm->vm_from_config)
vm->vm_params.vmc_ncpus = vm->vm_ncpus_config;
@@ -290,6 +291,8 @@ vmd_dispatch_control(int fd, struct priv
memset(&vmr, 0, sizeof(vmr));
vmr.vmr_result = res;
vmr.vmr_id = vm_id;
+ strlcpy(vmr.vmr_ifname, failed_ifname,
+ sizeof(vmr.vmr_ifname));
if (proc_compose_imsg(ps, PROC_CONTROL, cmd, peer_id, -1,
&vmr, sizeof(vmr)) == -1)
return (-1);
@@ -410,7 +413,7 @@ vmd_dispatch_vmm(int fd, struct privsep_
} else {
/* Stop VM instance but keep the tty open */
vm_stop(vm, 1, __func__);
- config_setvm(ps, vm, (uint32_t)-1, vm->vm_uid);
+ config_setvm(ps, vm, (uint32_t)-1, vm->vm_uid, NULL);
}
/* The error is meaningless for deferred responses */
@@ -787,7 +790,8 @@ start_vm_batch(int fd, short type, void
break;
}
vm->vm_state &= ~VM_STATE_WAITING;
- config_setvm(&env->vmd_ps, vm, -1, vm->vm_params.vmc_owner.uid);
+ config_setvm(&env->vmd_ps, vm, -1,
+ vm->vm_params.vmc_owner.uid, NULL);
}
log_debug("%s: done starting vms", __func__);
}
@@ -1811,6 +1815,7 @@ vmop_result_read(struct imsg *imsg, stru
fatal("%s", __func__);
vmr->vmr_ttyname[sizeof(vmr->vmr_ttyname) - 1] = '\0';
+ vmr->vmr_ifname[sizeof(vmr->vmr_ifname) - 1] = '\0';
}
void
Index: usr.sbin/vmd/vmd.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/vmd.h,v
diff -u -p -a -u -r1.154 vmd.h
--- usr.sbin/vmd/vmd.h 5 Oct 2026 23:07:37 -0000 1.154
+++ usr.sbin/vmd/vmd.h 13 Oct 2026 08:43:39 -0000
@@ -157,6 +157,7 @@ struct vmop_result {
uint32_t vmr_id;
pid_t vmr_pid;
char vmr_ttyname[VM_TTYNAME_MAX];
+ char vmr_ifname[IF_NAMESIZE];
};
struct vmop_info_result {
@@ -580,7 +581,8 @@ void config_purge(struct vmd *, unsigne
int config_setconfig(struct vmd *);
int config_getconfig(struct vmd *, struct imsg *);
int config_setreset(struct vmd *, unsigned int);
-int config_setvm(struct privsep *, struct vmd_vm *, uint32_t, uid_t);
+int config_setvm(struct privsep *, struct vmd_vm *, uint32_t, uid_t,
+ char *);
int config_getvm(struct privsep *, struct imsg *);
int config_getdisk(struct privsep *, struct imsg *);
int config_getif(struct privsep *, struct imsg *);