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