diff options
author | Dave Voutila <dv@cvs.openbsd.org> | 2023-04-28 19:46:43 +0000 |
---|---|---|
committer | Dave Voutila <dv@cvs.openbsd.org> | 2023-04-28 19:46:43 +0000 |
commit | c6132cfad55574e0b25d1ce0002e634d80d445df (patch) | |
tree | a858b01a2f10f82db74cc6bbf073b1236f279158 /usr.sbin/vmctl | |
parent | bfbe96e3e8b68c8d0791af5113636aea4c6094be (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.c | 8 | ||||
-rw-r--r-- | usr.sbin/vmctl/vmctl.c | 28 |
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); |