James Cook writes:
> Currently, "vmctl create -i source.qcow2 dest.qcow" fails when > source.qcow2 has a base image, because virtio_qcow2_get_base calls > realpath which doesn't interact well with unveil. > > The below patch fixes it by delaying the first call to unveil. Caveat: > I have never worked with unveil or any of this code before, but the > change seems simple enough. I believe the correct fix here is to unveil the base image in the virtio_qcow2_get_base function in vioqcow2.c and not move around all the unveil calls like you're doing. There's no reason to postpone them. I think virtio_qcow2_get_base is only used by vmctl (haven't confirmed) but if so it should be safe to add the unveil call there. I did a quick 1-line change and checked that it at least resolves the error you're reporting. > > I also documented a quirk of the "vmctl create" command: when the -b > option is specified, the "disk" argument had better be in the current > directory. (Otherwise for example vmd won't be able to open the image.) > You mention both vmctl(8) and vmd(8). Where is the problem? When you start a guest with vmd(8) or when you're running "vmctl create"? > The patch includes a regression test that demonstrates the existing > problem. > > > > diff --git a/regress/usr.sbin/Makefile b/regress/usr.sbin/Makefile > index 60e2178d3c7..146f9c9f322 100644 > --- a/regress/usr.sbin/Makefile > +++ b/regress/usr.sbin/Makefile > @@ -15,6 +15,7 @@ SUBDIR += rpki-client > SUBDIR += snmpd > SUBDIR += switchd > SUBDIR += syslogd > +SUBDIR += vmctl > > .if ${MACHINE} == "amd64" || ${MACHINE} == "i386" > SUBDIR += vmd > diff --git a/regress/usr.sbin/vmctl/Makefile b/regress/usr.sbin/vmctl/Makefile > new file mode 100644 > index 00000000000..108ff0a43c4 > --- /dev/null > +++ b/regress/usr.sbin/vmctl/Makefile > @@ -0,0 +1,18 @@ > +# $OpenBSD$ > + > +REGRESS_TARGETS=convert_with_absolute_base_path convert_with_local_base_paths > + > +convert_with_absolute_base_path: > + rm *.qcow2 > + vmctl create -s 1m base.qcow2 > + vmctl create -b ${PWD}/base.qcow2 source.qcow2 > + vmctl create -i source.qcow2 dest.qcow2 > + > +convert_with_local_base_paths: > + rm *.qcow2 > + vmctl create -s 1m base0.qcow2 > + vmctl create -b base0.qcow2 base1.qcow2 > + vmctl create -b base1.qcow2 source.qcow2 > + vmctl create -i source.qcow2 dest.qcow2 > + > +.include <bsd.regress.mk> > diff --git a/usr.sbin/vmctl/main.c b/usr.sbin/vmctl/main.c > index 249eaa3ded1..2d713d67274 100644 > --- a/usr.sbin/vmctl/main.c > +++ b/usr.sbin/vmctl/main.c > @@ -575,8 +575,7 @@ ctl_create(struct parse_result *res, int argc, char > *argv[]) > break; > case 'i': > input = optarg; > - if (unveil(input, "r") == -1) > - err(1, "unveil"); > + /* Don't call unveil before ctl_convert. */ > break; > case 's': > if (parse_size(res, optarg) != 0) > @@ -597,8 +596,6 @@ ctl_create(struct parse_result *res, int argc, char > *argv[]) > > if (pledge("stdio rpath wpath cpath unveil", NULL) == -1) > err(1, "pledge"); > - if (unveil(disk, "rwc") == -1) > - err(1, "unveil"); > > if (input) { > if (base && input) > @@ -606,6 +603,8 @@ ctl_create(struct parse_result *res, int argc, char > *argv[]) > return ctl_convert(input, disk, type, res->size); > } > > + if (unveil(disk, "rwc") == -1) > + err(1, "unveil"); > if (unveil(NULL, NULL)) > err(1, "unveil"); > > @@ -656,7 +655,10 @@ ctl_convert(const char *srcfile, const char *dstfile, > int dsttype, size_t dstsiz > goto done; > } > > - /* We can only lock unveil after opening the disk and all base images */ > + /* We can't call unveil before open_imagefile, since it might call > + virtio_qcow2_get_base. */ > + if (unveil(dst.disk, "rwc") == -1) > + err(1, "unveil"); > if (unveil(NULL, NULL)) > err(1, "unveil"); > > diff --git a/usr.sbin/vmctl/vmctl.8 b/usr.sbin/vmctl/vmctl.8 > index d36170e3e24..42cde19544b 100644 > --- a/usr.sbin/vmctl/vmctl.8 > +++ b/usr.sbin/vmctl/vmctl.8 > @@ -77,7 +77,7 @@ connect to the console of the VM with the specified > Create a VM disk image file with the specified > .Ar disk > path. > -.Bl -tag -width "-i input" > +.Bl -tag -width "-i disk" > .It Fl b Ar base > For > .Sq qcow2 , > @@ -85,7 +85,9 @@ a > .Ar base > image may be specified. > The base image is not modified and the derived image contains only the > -changes written by the VM. > +changes written by the VM. When using this option, > +.Ar disk > +should be in the current directory. > .It Fl i Ar disk > Copy and convert the input > .Ar disk > diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c > index d8edbc062eb..3b217121a14 100644 > --- a/usr.sbin/vmctl/vmctl.c > +++ b/usr.sbin/vmctl/vmctl.c > @@ -847,6 +847,9 @@ vm_console(struct vmop_info_result *list, size_t ct) > * > * Open an imagefile with the specified type, path and size. > * > + * Do not call unveil before this function, in case virtio_qcow2_get_base > + * needs to resolve base images. (This function does call unveil.) > + * > * Parameters: > * type : format of the image file > * imgfile_path: path to the image file to create > @@ -885,14 +888,6 @@ open_imagefile(int type, const char *imgfile_path, int > flags, > } else if (ret == 0) > break; > > - /* > - * This might be called after unveil is already > - * locked but it is save to ignore the EPERM error > - * here as the subsequent open would fail as well. > - */ > - if ((ret = unveil(path, "r")) != 0 && > - (ret != EPERM)) > - err(1, "unveil"); > if ((basefd[i + 1] = open(path, O_RDONLY)) == -1) { > log_warn("%s: failed to open base %s", > __func__, path); -- -Dave Voutila