From: "Daniel P. Berrangé" <berrange@redhat.com>
To: Peter Xu <peterx@redhat.com>
Cc: Ben Chaney <bchaney@akamai.com>,
farosas@suse.de, armbru@redhat.com, mark.kanda@oracle.com,
qemu-devel@nongnu.org, johunt@akamai.com, mtottenh@akamai.com,
nhudson@akamai.com
Subject: Re: [PATCH] migration: cpr socket permissions fix
Date: Fri, 21 Nov 2025 16:54:23 +0000 [thread overview]
Message-ID: <aSCZP_mkjYD7e7nP@redhat.com> (raw)
In-Reply-To: <aSCOVNMJ-NK_9PuH@x1.local>
On Fri, Nov 21, 2025 at 11:07:48AM -0500, Peter Xu wrote:
> On Thu, Nov 20, 2025 at 01:57:33PM -0500, Ben Chaney wrote:
> > Fix an issue where cpr transfer fails when running with the
> > -run-with user=$USERID with a permission denied error. This issue
> > occurs because the destination host creates the transfer sockets before
> > it drops permissions while the source host tries to connect after
> > dropping permissions. Fix this by changing the ownership of the cpr
> > socket to the lower level so it is accessible to both parties.
> >
> > Resolves: https://lore.kernel.org/all/3D32B62F-29E2-4470-86A5-9A2B3B29E371@akamai.com/
> > Signed-off-by: Ben Chaney <bchaney@akamai.com>
> > ---
> > include/system/os-posix.h | 1 +
> > include/system/os-wasm.h | 1 +
> > include/system/os-win32.h | 1 +
> > os-posix.c | 12 ++++++++++++
> > stubs/meson.build | 1 +
> > stubs/os-file.c | 6 ++++++
> > util/qemu-sockets.c | 6 ++++++
> > 7 files changed, 28 insertions(+)
> > create mode 100644 stubs/os-file.c
> >
> > diff --git a/include/system/os-posix.h b/include/system/os-posix.h
> > index ce5b3bccf8..e4b69fc316 100644
> > --- a/include/system/os-posix.h
> > +++ b/include/system/os-posix.h
> > @@ -54,6 +54,7 @@ void os_set_chroot(const char *path);
> > void os_setup_limits(void);
> > void os_setup_post(void);
> > int os_mlock(bool on_fault);
> > +void os_set_socket_permissions(const char *path);
> >
> > /**
> > * qemu_alloc_stack:
> > diff --git a/include/system/os-wasm.h b/include/system/os-wasm.h
> > index 3abb3aaa03..eeac092183 100644
> > --- a/include/system/os-wasm.h
> > +++ b/include/system/os-wasm.h
> > @@ -57,6 +57,7 @@ static inline int os_set_daemonize(bool d)
> > };
> > bool is_daemonized(void);
> > static inline void os_daemonize(void) {}
> > +static inline void os_set_socket_permissions(const char *dummy) {};
> >
> > /**
> > * qemu_alloc_stack:
> > diff --git a/include/system/os-win32.h b/include/system/os-win32.h
> > index 22d72babdf..79e42ec297 100644
> > --- a/include/system/os-win32.h
> > +++ b/include/system/os-win32.h
> > @@ -103,6 +103,7 @@ static inline void os_setup_post(void) {}
> > static inline void os_set_proc_name(const char *dummy) {}
> > void os_set_line_buffering(void);
> > void os_setup_early_signal_handling(void);
> > +static inline void os_set_socket_permissions(const char *dummy) {};
> >
> > int getpagesize(void);
> >
> > diff --git a/os-posix.c b/os-posix.c
> > index 52925c23d3..bbd17ff2b9 100644
> > --- a/os-posix.c
> > +++ b/os-posix.c
> > @@ -94,6 +94,18 @@ static struct passwd *user_pwd; /* NULL non-NULL NULL */
> > static uid_t user_uid = (uid_t)-1; /* -1 -1 >=0 */
> > static gid_t user_gid = (gid_t)-1; /* -1 -1 >=0 */
> >
> > +void os_set_socket_permissions(const char *path)
> > +{
> > + uid_t uid = user_pwd ? user_pwd->pw_uid : user_uid;
> > + gid_t gid = user_pwd ? user_pwd->pw_gid : user_gid;
> > +
> > + if (chown(path, uid, gid) < 0) {
> > + error_report("Failed to chown socket %s: %s", path, strerror(errno));
> > + exit(1);
> > + }
> > +}
> > +
> > +
> > /*
> > * Prepare to change user ID. user_id can be one of 3 forms:
> > * - a username, in which case user ID will be changed to its uid,
> > diff --git a/stubs/meson.build b/stubs/meson.build
> > index 0b2778c568..4a4342344b 100644
> > --- a/stubs/meson.build
> > +++ b/stubs/meson.build
> > @@ -24,6 +24,7 @@ if have_block
> > stub_ss.add(files('ram-block.c'))
> > stub_ss.add(files('runstate-check.c'))
> > stub_ss.add(files('uuid.c'))
> > + stub_ss.add(files('os-file.c'))
> > endif
> >
> > if have_block or have_ga
> > diff --git a/stubs/os-file.c b/stubs/os-file.c
> > new file mode 100644
> > index 0000000000..c32cbc7efa
> > --- /dev/null
> > +++ b/stubs/os-file.c
> > @@ -0,0 +1,6 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +#include "qemu/osdep.h"
> > +
> > +void os_set_socket_permissions(const char *dummy)
> > +{
> > +}
> > diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
> > index 4773755fd5..77b2d9287b 100644
> > --- a/util/qemu-sockets.c
> > +++ b/util/qemu-sockets.c
> > @@ -1026,6 +1026,12 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
> > error_setg_errno(errp, errno, "Failed to bind socket to %s", path);
> > goto err;
> > }
> > + /*
> > + * Change the permissions on the socket to match the permission of the
> > + * counterparty process
> > + */
> > + os_set_socket_permissions(un.sun_path);
>
> QEMU's -run-with described user= as:
>
> user=username or user=uid:gid can be used to drop root privileges before
> starting guest execution. QEMU will use the setuid and setgid system
> calls to switch to the specified identity...
>
> So it explicitly mentioned "before starting guest execution", hence at
> least from that doc it's hard to say if unix socket should be created with
> the privilege or after dropped.. Here I believe cpr socket should be the
> case for latter, however when it's a generic change to unix listening
> ports, I wonder if there's other unwanted side effects.
>
> Considering unix socket itself doesn't really have a UID attached to it,
> it's only the unix path that needs a chmod(), meanwhile the mgmt of course
> knows both the right UID (as specified in -run-with) and the path, would it
> make sense if the mgmt chmod() after it starts dest QEMU? That'll reduce
> the scope of impact to minimum.
My guiding principal is that the behaviour of cold-plugging a backend
on the CLI and hot-plugging a backend via QMP should be the same, since
we want to eventually get to a point where everything can be configured
via QMP and zero CLI except for basic process related things.
hot-plugging will honour -run-with setting, therefore cold-plugging
should do the same.
Having said that, the run-with setting impl is very clearcut however
that it is intended to run *after* all cold-plug setup is complete.
IOW, it is inherantly intending to have differnt behaviour for cold
plug vs hotplug.
There's a very real risk we'll cause regressions if we change how
permissions are handled implicitly on any backends.
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 :|
prev parent reply other threads:[~2025-11-22 4:27 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-20 18:57 [PATCH] migration: cpr socket permissions fix Ben Chaney
2025-11-21 16:07 ` Peter Xu
2025-11-21 16:54 ` Daniel P. Berrangé [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aSCZP_mkjYD7e7nP@redhat.com \
--to=berrange@redhat.com \
--cc=armbru@redhat.com \
--cc=bchaney@akamai.com \
--cc=farosas@suse.de \
--cc=johunt@akamai.com \
--cc=mark.kanda@oracle.com \
--cc=mtottenh@akamai.com \
--cc=nhudson@akamai.com \
--cc=peterx@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).