summaryrefslogtreecommitdiff
path: root/usr.sbin/vmctl
diff options
context:
space:
mode:
authorDave Voutila <dv@cvs.openbsd.org>2023-04-28 19:46:43 +0000
committerDave Voutila <dv@cvs.openbsd.org>2023-04-28 19:46:43 +0000
commitc6132cfad55574e0b25d1ce0002e634d80d445df (patch)
treea858b01a2f10f82db74cc6bbf073b1236f279158 /usr.sbin/vmctl
parentbfbe96e3e8b68c8d0791af5113636aea4c6094be (diff)
vmd(8)/vmctl(8): allow vm owners to override boot kernel.
vmd allows non-root users to "own" a vm defined in vm.conf(5). While the user can start/stop the vm, if they break their filesystem they have no means of booting recovery media like a ramdisk kernel. This change opens the provided boot kernel via vmctl and passes the file descriptor through the control channel to vmd. The next boot of the vm will use the provided file descriptor as boot kernel/bios. Subsequent boots (e.g. a reboot) will return to using behavior defined in vm.conf or the default bios image. ok mlarkin@
Diffstat (limited to 'usr.sbin/vmctl')
-rw-r--r--usr.sbin/vmctl/main.c8
-rw-r--r--usr.sbin/vmctl/vmctl.c28
2 files changed, 26 insertions, 10 deletions
diff --git a/usr.sbin/vmctl/main.c b/usr.sbin/vmctl/main.c
index c1b04c510ec..b4c10561d90 100644
--- a/usr.sbin/vmctl/main.c
+++ b/usr.sbin/vmctl/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.74 2023/04/25 12:51:07 dv Exp $ */
+/* $OpenBSD: main.c,v 1.75 2023/04/28 19:46:41 dv Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -81,7 +81,7 @@ struct ctl_command ctl_commands[] = {
{ "show", CMD_STATUS, ctl_status, "[id]" },
{ "start", CMD_START, ctl_start,
"[-cL] [-B device] [-b path] [-d disk] [-i count]\n"
- "\t\t[-m size] [-n switch] [-r path] [-t name] id | name" },
+ "\t\t[-m size] [-n switch] [-r path] [-t name] id | name", 1},
{ "status", CMD_STATUS, ctl_status, "[id]" },
{ "stop", CMD_STOP, ctl_stop, "[-fw] [id | -a]" },
{ "unpause", CMD_UNPAUSE, ctl_unpause, "id" },
@@ -820,6 +820,10 @@ ctl_start(struct parse_result *res, int argc, char *argv[])
char path[PATH_MAX];
const char *s;
+ /* We may require sendfd */
+ if (pledge("stdio rpath exec unix getpw unveil sendfd", NULL) == -1)
+ err(1, "pledge");
+
while ((ch = getopt(argc, argv, "b:B:cd:i:Lm:n:r:t:")) != -1) {
switch (ch) {
case 'b':
diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c
index c4992985bfc..66b7d271896 100644
--- a/usr.sbin/vmctl/vmctl.c
+++ b/usr.sbin/vmctl/vmctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmctl.c,v 1.86 2023/04/25 12:51:07 dv Exp $ */
+/* $OpenBSD: vmctl.c,v 1.87 2023/04/28 19:46:41 dv Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
@@ -81,6 +81,15 @@ vm_start(uint32_t start_id, const char *name, size_t memsize, int nnics,
int i;
const char *s;
+ if (kernel) {
+ if (unveil(kernel, "r") == -1)
+ err(1, "unveil boot kernel");
+ } else {
+ /* We can drop sendfd promise. */
+ if (pledge("stdio rpath exec unix getpw unveil", NULL) == -1)
+ err(1, "pledge");
+ }
+
if (memsize)
flags |= VMOP_CREATE_MEMORY;
if (nnics)
@@ -98,7 +107,7 @@ vm_start(uint32_t start_id, const char *name, size_t memsize, int nnics,
memsize = VM_DEFAULT_MEMORY;
if (ndisks > VM_MAX_DISKS_PER_VM)
errx(1, "too many disks");
- else if (ndisks == 0)
+ else if (kernel == NULL && ndisks == 0)
warnx("starting without disks");
if (kernel == NULL && ndisks == 0 && !iso)
errx(1, "no kernel or disk/cdrom specified");
@@ -106,13 +115,13 @@ vm_start(uint32_t start_id, const char *name, size_t memsize, int nnics,
nnics = 0;
if (nnics > VM_MAX_NICS_PER_VM)
errx(1, "too many network interfaces");
- if (nnics == 0)
+ if (kernel == NULL && nnics == 0)
warnx("starting without network interfaces");
}
if ((vmc = calloc(1, sizeof(struct vmop_create_params))) == NULL)
return (ENOMEM);
-
+ vmc->vmc_kernel = -1;
vmc->vmc_flags = flags;
/* vcp includes configuration that is shared with the kernel */
@@ -173,10 +182,13 @@ vm_start(uint32_t start_id, const char *name, size_t memsize, int nnics,
sizeof(vcp->vcp_name)) >= sizeof(vcp->vcp_name))
errx(1, "vm name too long");
}
- if (kernel != NULL)
- if (strlcpy(vmc->vmc_kernel, kernel,
- sizeof(vmc->vmc_kernel)) >= sizeof(vmc->vmc_kernel))
+ if (kernel != NULL) {
+ if (strnlen(kernel, PATH_MAX) == PATH_MAX)
errx(1, "kernel name too long");
+ vmc->vmc_kernel = open(kernel, O_RDONLY);
+ if (vmc->vmc_kernel == -1)
+ err(1, "cannot open kernel '%s'", kernel);
+ }
if (iso != NULL)
if (strlcpy(vmc->vmc_cdrom, iso,
sizeof(vmc->vmc_cdrom)) >= sizeof(vmc->vmc_cdrom))
@@ -187,7 +199,7 @@ vm_start(uint32_t start_id, const char *name, size_t memsize, int nnics,
errx(1, "instance vm name too long");
vmc->vmc_bootdevice = bootdevice;
- imsg_compose(ibuf, IMSG_VMDOP_START_VM_REQUEST, 0, 0, -1,
+ imsg_compose(ibuf, IMSG_VMDOP_START_VM_REQUEST, 0, 0, vmc->vmc_kernel,
vmc, sizeof(struct vmop_create_params));
free(vcp);