[libvirt PATCH] qemu: Allow sockets in long or deep paths.
Daniel P. Berrangé
berrange at redhat.com
Tue Apr 18 08:12:53 UTC 2023
On Tue, Apr 18, 2023 at 02:59:26AM -0400, Nick Guenther wrote:
> The qemu driver creates IPC sockets using absolute paths,
> but under POSIX socket paths are constrained pretty tightly.
> On systems with homedirs on an unusual mount point, like
> network homedirs, or just particularly long usernames, this
> could make starting VMs under qemu:///session impossible.
>
> Resolves https://gitlab.com/libvirt/libvirt/-/issues/466
Example path from that bug
/home/WAVES.EXAMPLE.ORG/u123456/.config/libvirt/qemu/channel/target/domain-11-alpinelinux3.14/org.qemu.guest_agent.0
IMHO the key problem here is not your $HOME location, but rather
libvirt being ridiculously verbose in the nested dir structuion
Looking at the pieces
* /home/WAVES.EXAMPLE.ORG/u123456 -> 31 chars
$HOME, we can't change this
* /.config/libvirt/qemu -> 21 chars
Libvirt's config directory scope to the driver, we don't
want to change this
* /channel/target/domain-11-alpinelinux3.14 => 42 chars
Arbitrarily inventing nesting for the sockets, we can
change at will
* /org.qemu.guest_agent.0 -> 23 chars
Either user specified, or matches the port name, ideally
don't change this
So we've got 31 + 21 + 23 == 75 chars we don't want to /can't
change, but that leaves 33 to play with
I feel like having 'domain-' in the path is redudant as
everything under /channel is for a domain. Having 'target'
also feels redundant to me.
We could use '/channel/tgt-11-alpinelinux3.14' == 31 chars
or just /channel/11-alpinelinux3.14 == 27 chars, which
gives extra scope for a longer $HOME.
>
> Signed-off-by: Nick Guenther <nick.guenther at polymtl.ca>
> ---
> src/qemu/qemu_command.c | 52 ++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 49 insertions(+), 3 deletions(-)
>
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 4ca93bf3dc..3f180d5fb6 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -53,6 +53,7 @@
> #include "virmdev.h"
> #include "virutil.h"
>
> +#include <libgen.h>
> #include <sys/stat.h>
> #include <fcntl.h>
>
> @@ -4866,6 +4867,37 @@ qemuOpenChrChardevUNIXSocket(const virDomainChrSourceDef *dev)
> struct sockaddr_un addr;
> socklen_t addrlen = sizeof(addr);
> int fd;
> + char* wd = NULL;
> + char* socket_dir_c = NULL;
> + char* socket_name_c = NULL;
> + char* socket_dir = NULL;
> + char* socket_name = NULL;
> +
> + /* The path length is limited to what fits in sockaddr_un.
> + * It's pretty short: 108 on Linux, and this is too easy to hit.
> + * Work around this limit by using a *relative path*.
> + *
> + * background: https://stackoverflow.com/questions/34829600/why-is-the-maximal-path-length-allowed-for-unix-sockets-on-linux-108
> + *
> + * docker added a different workaround: https://github.com/moby/moby/pull/13408
> + */
> + if ((wd = getcwd(NULL, 0)) == NULL) {
> + virReportSystemError(errno, "%s",
> + _("Unable to get working directory"));
> + goto error;
> + }
> +
> + socket_dir_c = strdup(dev->data.nix.path); // dirname edits the string given it, so it must be copied
> + socket_name_c = strdup(dev->data.nix.path);
> +
> + socket_dir = dirname(socket_dir_c);
> + socket_name = basename(socket_name_c);
> +
> + if (chdir(socket_dir) < 0) {
> + virReportSystemError(errno, "%s",
> + _("Unable to get change to socket directory"));
> + goto error;
> + }
>
> if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
> virReportSystemError(errno, "%s",
> @@ -4875,10 +4907,10 @@ qemuOpenChrChardevUNIXSocket(const virDomainChrSourceDef *dev)
>
> memset(&addr, 0, sizeof(addr));
> addr.sun_family = AF_UNIX;
> - if (virStrcpyStatic(addr.sun_path, dev->data.nix.path) < 0) {
> + if (virStrcpyStatic(addr.sun_path, socket_name) < 0) {
> virReportError(VIR_ERR_INTERNAL_ERROR,
> - _("UNIX socket path '%1$s' too long"),
> - dev->data.nix.path);
> + _("UNIX socket name '%1$s' too long"),
> + socket_name);
> goto error;
> }
>
> @@ -4909,9 +4941,23 @@ qemuOpenChrChardevUNIXSocket(const virDomainChrSourceDef *dev)
> if (virFileUpdatePerm(dev->data.nix.path, 0002, 0664) < 0)
> goto error;
>
> + /* restore working directory */
> + if (chdir(wd) < 0) {
> + virReportSystemError(errno, "%s",
> + _("Unable to restore working directory"));
> + goto error;
> + }
> +
> + free(socket_name_c);
> + free(socket_dir_c);
> + free(wd);
> +
> return fd;
>
> error:
> + if (socket_name_c != NULL) { free(socket_name_c); }
> + if (socket_dir_c != NULL) { free(socket_dir_c); }
> + if (wd != NULL) { free(wd); }
> VIR_FORCE_CLOSE(fd);
> return -1;
> }
> --
> 2.34.1
>
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
More information about the libvir-list
mailing list