On Mon, Mar 15, 2021 at 08:21:56AM +0000, James Cook wrote:
> Hi tech@,
>
> The below patch removes calls to realpath(3) when looking up a qcow2
> base image. Previous thread:
> https://marc.info/?t=161562496400002&r=1&w=2
>
> In short, the calls were failing inside vmctl, because of unveil. The
> other thread has alternative solutions but I think this is simplest.
>
> I included a regression test demonstrating the vmctl bug, in case
> there's interest. I tested vmd manually as described in the other
> thread.
>
> I also added a check in case dirname(3) fails --- I don't think it
> currently can, but better safe than sorry, I figure. (Noticed by Dave
> in the other thread.)
>
> - James
>

After looking at this a bit, we decided to remove the unveil parts around
the base images, since the realpath removal below would also affect vmd.

dv@ just committed that. Thanks for the diff and research!

>
> 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..8fa87f0f6f0
> --- /dev/null
> +++ b/regress/usr.sbin/vmctl/Makefile
> @@ -0,0 +1,34 @@
> +# $OpenBSD$
> +
> +REGRESS_TARGETS = run-regress-convert-with-base-path
> +
> +run-regress-convert-with-base-path:
> +     # non-relative base path
> +     rm -f *.qcow2
> +     vmctl create -s 1m base.qcow2
> +     vmctl create -b ${PWD}/base.qcow2 source.qcow2
> +     vmctl create -i source.qcow2 dest.qcow2
> +
> +     # relative base path; two base images
> +     rm -f *.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
> +
> +     # copy from a different directory
> +     rm -rf dir *.qcow2
> +     vmctl create -s 1m base.qcow2
> +     vmctl create -b base.qcow2 source.qcow2
> +     mkdir dir
> +     cd dir; vmctl create -i ../source.qcow2 dest.qcow2
> +
> +     # base accessed through symlink
> +     rm -rf dir sym *.qcow2
> +     mkdir dir
> +     cd dir; vmctl create -s 1m base.qcow2
> +     cd dir; vmctl create -b base.qcow2 source.qcow2
> +     ln -s dir sym
> +     vmctl create -i sym/source.qcow2 dest.qcow2
> +
> +.include <bsd.regress.mk>
> diff --git a/usr.sbin/vmd/vioqcow2.c b/usr.sbin/vmd/vioqcow2.c
> index 34d0f116cc4..be8609f1644 100644
> --- a/usr.sbin/vmd/vioqcow2.c
> +++ b/usr.sbin/vmd/vioqcow2.c
> @@ -145,8 +145,8 @@ virtio_qcow2_init(struct virtio_backing *file, off_t 
> *szp, int *fd, size_t nfd)
>  ssize_t
>  virtio_qcow2_get_base(int fd, char *path, size_t npath, const char *dpath)
>  {
> +     char pathbuf[PATH_MAX];
>       char dpathbuf[PATH_MAX];
> -     char expanded[PATH_MAX];
>       struct qcheader header;
>       uint64_t backingoff;
>       uint32_t backingsz;
> @@ -180,27 +180,23 @@ virtio_qcow2_get_base(int fd, char *path, size_t npath, 
> const char *dpath)
>        * rather than relative to the directory vmd happens to be running in,
>        * since this is the only userful interpretation.
>        */
> -     if (path[0] == '/') {
> -             if (realpath(path, expanded) == NULL ||
> -                 strlcpy(path, expanded, npath) >= npath) {
> -                     log_warnx("unable to resolve %s", path);
> +     if (path[0] != '/') {
> +             if (strlcpy(pathbuf, path, sizeof(pathbuf)) >=
> +                 sizeof(pathbuf)) {
> +                     log_warnx("path too long: %s", path);
>                       return -1;
>               }
> -     } else {
>               if (strlcpy(dpathbuf, dpath, sizeof(dpathbuf)) >=
>                   sizeof(dpathbuf)) {
>                       log_warnx("path too long: %s", dpath);
>                       return -1;
>               }
> -             s = dirname(dpathbuf);
> -             if (snprintf(expanded, sizeof(expanded),
> -                 "%s/%s", s, path) >= (int)sizeof(expanded)) {
> -                     log_warnx("path too long: %s/%s", s, path);
> +             if ((s = dirname(dpathbuf)) == NULL) {
> +                     log_warn("dirname");
>                       return -1;
>               }
> -             if (npath < PATH_MAX ||
> -                 realpath(expanded, path) == NULL) {
> -                     log_warnx("unable to resolve %s", path);
> +             if (snprintf(path, npath, "%s/%s", s, pathbuf) >= (int)npath) {
> +                     log_warnx("path too long: %s/%s", s, path);
>                       return -1;
>               }
>       }
>

Reply via email to