[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [XEN PATCH 1/1] tools/libxl: search PATH for QEMU if `QEMU_XEN_PATH` is not absolute
On Mon, Dec 23, 2024 at 11:17:53AM +0800, Hongbo wrote: > `QEMU_XEN_PATH` will be configured as `qemu-system-i386` with no clue where, > if > `--with-system-qemu` is set without giving a path (as matched in the case > `yes` > but not `*`). However, the existence of the executable is checked by > `access()`, > that will not look for anywhere in $PATH but the current directory. And since > it > is possible for `qemu-system-i386` (or any other configured values) to be > executed from PATH later, we'd better find that in PATH and return the full > path > for the caller to check against. > > Signed-off-by: Hongbo <hehongbo@xxxxxxxx> > > --- > > This patch is from the maintenance team of the Xen Project Hypervisor at > NixOS. > We encountered this and thought it was an edge case, and came up with this > while > maintaining the package and module of the Hypervisor at NixOS. > > According to `xen.git/tools/configure.ac`, `QEMU_XEN_PATH` will be configured > as > `qemu-system-i386` (relative) if `--with-system-qemu` is set (as `yes`) but > without an absolute path. However, it will execute `qemu-system-i386` from the > `PATH` only if a file is called `qemu-system-i386` in the *current directory*. > That is because the existence of the device model executable file, in this > case > `qemu-system-i386`, is checked via `access()` without concatenating it with > current PATHs. And `access()` is not tailored for executables, it will not > search for the PATHs for us. > > See `libxl__domain_build_info_setdefault()` at > `xen.git/tools/libs/light/libxl_create.c`. It reads `dm` from > `libxl__domain_device_model()` and then uses `access()` on it. If that fails, > it > will modify the `device_model_version` to qemu-traditional. Then, in > `libxl__spawn_local_dm()` at `xen.git/tools/lib/light/libxl_dm.c`, it reads > from > `libxl__domain_device_model()` again, and `access()` is used again to detect > the > file's existence. In my investigations, if I comment out these 2 existence > checks then it will run `qemu-system-i386` from the current PATH without > issues. > I guess if it's not blocked by those 2 checks, it will finally reach > `libxl__exec()`. Then, inside the `libxl__exec()` the device model executable > will be executed by `execvp()`, which can certainly call the executable from > both absolute paths and current PATHs. > > Since the device model executable will be checked twice, both of which will > call > `libxl__domain_device_model()` to get its location, I think the preferred > solution would be patching the `libxl__domain_device_model()` function itself > to > tell if we're referring to an executable in PATHs, and resolve to the full > path > of it for the caller to check against. > > It's indeed an edge case. But why would we need this? Because in Nix (the > package manager) and NixOS, we use Nix expressions to declare dependencies on > the dependents, and we ran into the issue of circular dependency - to build > QEMU with Xen support, we should give the Xen header and libraries into the > building process of QEMU, that makes Xen (`pkgs.xen`) a dependency of QEMU > (`pkgs.qemu_xen`), which prevents us from using `pkgs.qemu_xen` in the > building > process of Xen, and in `--with-system-qemu=` argument in particular. It is > very > different compared to those distros and package managers that follow the > Filesystem Hierarchy Standard (FHS), in which Xen can be built with > `--with-system-qemu=` points to a non-existent FHS location of > `qemu-system-i386`, and then use these Xen libraries from the artifacts to > build > QEMU afterward. So we decide to build Xen with `--with-system-qemu` but not > including an executable path, taking advantage of the fact that > `QEMU_XEN_PATH` > can be configured as a relative `qemu-system-i386` when omitted, as declared > as > the `yes` case in `xen.git/tools/configure.ac`, and that results in we finding > the aforementioned "current directory" issue, and submitting this patch. Thanks. Sounds good, and also the feature seems half-way there already with the default to a binary name and the use of execvp. The patch looks mostly fine, I still have a few comments. > In the patch, I'm using the existence of slash (`/`) to tell if > `QEMU_XEN_PATH` > is relative, and begin to search in PATH if it is. I'm sort of iffy on this, > would it make more sense if we do this on inputs starting with a slash > instead? > And should we notify the user if it's not found anywhere in the PATH thus > proceeding with the value configured in `QEMU_XEN_PATH` as-is? Well, on one hand, that's how execvp() works, if there's a '/' in the path, search in $PATH is skipped. But that would be a buggy scenario because when you reboot a guest, the working directory isn't the same anymore, at least with `xl`. So if `pwd`/dir/qemu-dm exist when you execute `xl create`, but then run `reboot` in a guest, there's an "xl daemon" that would try to reboot the guest with /dir/qemu-dm because `pwd` would be just /. So I think checking that QEMU_XEN_PATH is absolute would be enough here. > Let me know if it's appropriate and if further changes are needed. > > Best regards, > Hongbo > > --- > CC: Anthony PERARD <anthony.perard@xxxxxxxxxx> > CC: Juergen Gross <jgross@xxxxxxxx> > --- > tools/libs/light/libxl_dm.c | 34 +++++++++++++++++++++++++++++++++- > 1 file changed, 33 insertions(+), 1 deletion(-) > > diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c > index 1f2f5bd97a..db05f20a5b 100644 > --- a/tools/libs/light/libxl_dm.c > +++ b/tools/libs/light/libxl_dm.c > @@ -332,7 +332,39 @@ const char *libxl__domain_device_model(libxl__gc *gc, > dm = libxl__abs_path(gc, "qemu-dm", > libxl__private_bindir_path()); > break; > case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN: > - dm = qemu_xen_path(gc); > + const char *configured_dm = qemu_xen_path(gc); Here, `clang` complained about that new variable, it expect an expression. Can you put the "case" in a block {} ? > + if (strchr(configured_dm, '/')) As discuste before, just checking for absolute path should be good enough here. > + dm = libxl__strdup(gc, configured_dm); The function used to return the value from qemu_xen_path(gc), so you can keep returning `configured_dm`, no need for an strdup, here or the two other strdup(configured_dm) below. Also as the `else` part have a block {}, it would be better to have a block {} for the "true" part of the `if` as well. > + else > + { > + const char *path_env = getenv("PATH"); > + if (!path_env) > + dm = libxl__strdup(gc, configured_dm); > + else > + { > + char *path_dup = libxl__strdup(gc, path_env); > + char *saveptr; > + > + char *path = strtok_r(path_dup, ":", &saveptr); > + char fullpath[PATH_MAX]; > + bool dm_found = false; > + while (path) > + { > + snprintf(fullpath, sizeof(fullpath), "%s/%s", path, > + configured_dm); > + if (access(fullpath, X_OK) == 0) > + { > + dm = libxl__strdup(gc, fullpath); > + dm_found = true; > + break; > + } > + path = strtok_r(NULL, ":", &saveptr); > + } > + > + if (!dm_found) > + dm = libxl__strdup(gc, configured_dm); > + } > + } > break; > default: > LOG(ERROR, "invalid device model version %d", Thanks, -- Anthony Perard | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |