All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450)
@ 2026-03-27 10:25 Cathy Hu
  2026-03-27 14:33 ` Daniel P. Berrangé
  0 siblings, 1 reply; 7+ messages in thread
From: Cathy Hu @ 2026-03-27 10:25 UTC (permalink / raw)
  To: qemu-devel; +Cc: Cathy Hu, Fabiano Rosas, KVM Bugs

From: Cathy Hu <cahu@suse.de>

Problem:

ATM the QEMU Guest Agent and SELinux are not working together properly.
The fedora (and therefor also the openSUSE) policy confine the qemu-guest-agent
service in the domain `qemu_ga_t`. That means, qemu-guest-agent
is only allowed to do what the policy says.

However, the `guest-exec` command allows arbitrary execution
of code from a privileged service, which conflicts with the
notion of SELinux confinement.

ATM, the policy allows only some accesses that are used
by other qemu-guest-agent commands.
That means, the qemu-guest-agent fails sporadically, depending
on what is allowed for other commands.
However, `guest-exec` would need to allow everything.

see https://bugzilla.suse.com/show_bug.cgi?id=1237450

Solution:

This is not an great solution, but it works like this:
We add a "wrapper" which is executed instead of the program
that is called via `guest-exec`. The "wrapper" just
re-executes the command given by `guest-exec`.
This way, on the SELinux policy side we can give that
wrapper executable a label on the file system.
With that label, we can transition into a more broader
unconfined domain _and_ toggle that transition with a
SELinux boolean. That would make `guest-exec`
consistently allowed to execute or not by policy.

This needs a change on the SELinux policy side to
accompany this with:
https://github.com/fedora-selinux/selinux-policy/pull/3122

What other options have been tried unsuccessfully:

- Fixing via SELinux policy: It is not possible for
  one domain to have different permissions depending on
  code path. It is also not possible to toggle the permissive
  state via a SELinux boolean, so users would need
  to add it via semanage.
- Setting the domain of the executed commands directly
  to a broader domain with setcon/setexeccon.
  The SELinux kernel does not allow to spawn a process
  directly with those that has broader privileges than the parent.

What other options are there to solve this issue:

- Making the qemu-guest-agent unconfined by default
- Document the workaround to use semanage to make the domain permissive
  if `exec-guest` is needed as works as intended and ignore the problem

Signed-off-by: Cathy Hu <cahu@suse.de>
---
 qga/commands.c               | 13 +++++++++++++
 qga/meson.build              |  7 +++++++
 qga/qemu-ga-selinux-helper.c | 17 +++++++++++++++++
 3 files changed, 37 insertions(+)
 create mode 100644 qga/qemu-ga-selinux-helper.c

diff --git a/qga/commands.c b/qga/commands.c
index 5f20af25d3..29c092630b 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -30,6 +30,10 @@
  */
 #define GUEST_FILE_READ_COUNT_MAX (48 * MiB)
 
+#ifdef CONFIG_SELINUX
+#define GUEST_EXEC_SELINUX_HELPER CONFIG_QEMU_HELPERDIR "/qemu-ga-selinux-helper"
+#endif
+
 /* Note: in some situations, like with the fsfreeze, logging may be
  * temporarily disabled. if it is necessary that a command be able
  * to log for accounting purposes, check ga_logging_enabled() beforehand.
@@ -418,6 +422,9 @@ GuestExec *qmp_guest_exec(const char *path,
     GuestExecInfo *gei;
     char **argv, **envp;
     strList arglist;
+#ifdef CONFIG_SELINUX
+    strList helper_arg;
+#endif
     gboolean ret;
     GError *gerr = NULL;
     gint in_fd, out_fd, err_fd;
@@ -439,7 +446,13 @@ GuestExec *qmp_guest_exec(const char *path,
         }
     }
 
+#ifdef CONFIG_SELINUX
+    helper_arg.value = get_relocated_path(GUEST_EXEC_SELINUX_HELPER);
+    helper_arg.next = &arglist;
+    argv = guest_exec_get_args(&helper_arg, true);
+#else
     argv = guest_exec_get_args(&arglist, true);
+#endif
     envp = has_env ? guest_exec_get_args(env, false) : NULL;
 
     flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD |
diff --git a/qga/meson.build b/qga/meson.build
index 89a4a8f713..61f60fba26 100644
--- a/qga/meson.build
+++ b/qga/meson.build
@@ -125,6 +125,13 @@ qga = executable('qemu-ga', qga_ss.sources() + qga_objs,
                  install: true)
 all_qga += qga
 
+if selinux.found()
+  qga_selinux_helper = executable('qemu-ga-selinux-helper', files('qemu-ga-selinux-helper.c'),
+             install: true,
+             install_dir: get_option('libexecdir'))
+  all_qga += qga_selinux_helper
+endif
+
 if host_os == 'windows'
   qemu_ga_msi_arch = {
     'x86': ['-D', 'Arch=32'],
diff --git a/qga/qemu-ga-selinux-helper.c b/qga/qemu-ga-selinux-helper.c
new file mode 100644
index 0000000000..a184e74ede
--- /dev/null
+++ b/qga/qemu-ga-selinux-helper.c
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <stdio.h>
+#include <glib.h>
+
+int main(int argc, char **argv)
+{
+    if (argc < 2) {
+        return EXIT_FAILURE;
+    }
+
+    execvp(argv[1], argv + 1);
+
+    int err = errno;
+    fprintf(stderr, "%s: %s\n", argv[1], strerror(err));
+
+    exit(EXIT_FAILURE);
+}
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450)
  2026-03-27 10:25 [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450) Cathy Hu
@ 2026-03-27 14:33 ` Daniel P. Berrangé
  2026-03-27 21:33   ` Kostiantyn Kostiuk
  2026-04-14 16:51   ` Martin Wilck
  0 siblings, 2 replies; 7+ messages in thread
From: Daniel P. Berrangé @ 2026-03-27 14:33 UTC (permalink / raw)
  To: Cathy Hu; +Cc: qemu-devel, Cathy Hu, Fabiano Rosas, KVM Bugs

On Fri, Mar 27, 2026 at 11:25:19AM +0100, Cathy Hu wrote:
> From: Cathy Hu <cahu@suse.de>
> 
> Problem:
> 
> ATM the QEMU Guest Agent and SELinux are not working together properly.
> The fedora (and therefor also the openSUSE) policy confine the qemu-guest-agent
> service in the domain `qemu_ga_t`. That means, qemu-guest-agent
> is only allowed to do what the policy says.
> 
> However, the `guest-exec` command allows arbitrary execution
> of code from a privileged service, which conflicts with the
> notion of SELinux confinement.
> 
> ATM, the policy allows only some accesses that are used
> by other qemu-guest-agent commands.
> That means, the qemu-guest-agent fails sporadically, depending
> on what is allowed for other commands.
> However, `guest-exec` would need to allow everything.
> 
> see https://bugzilla.suse.com/show_bug.cgi?id=1237450
> 
> Solution:
> 
> This is not an great solution, but it works like this:
> We add a "wrapper" which is executed instead of the program
> that is called via `guest-exec`. The "wrapper" just
> re-executes the command given by `guest-exec`.
> This way, on the SELinux policy side we can give that
> wrapper executable a label on the file system.
> With that label, we can transition into a more broader
> unconfined domain _and_ toggle that transition with a
> SELinux boolean. That would make `guest-exec`
> consistently allowed to execute or not by policy.
> 
> This needs a change on the SELinux policy side to
> accompany this with:
> https://github.com/fedora-selinux/selinux-policy/pull/3122
> 
> What other options have been tried unsuccessfully:
> 
> - Fixing via SELinux policy: It is not possible for
>   one domain to have different permissions depending on
>   code path. It is also not possible to toggle the permissive
>   state via a SELinux boolean, so users would need
>   to add it via semanage.
> - Setting the domain of the executed commands directly
>   to a broader domain with setcon/setexeccon.
>   The SELinux kernel does not allow to spawn a process
>   directly with those that has broader privileges than the parent.
> 
> What other options are there to solve this issue:
> 
> - Making the qemu-guest-agent unconfined by default
> - Document the workaround to use semanage to make the domain permissive
>   if `exec-guest` is needed as works as intended and ignore the problem

IMHO, the 'exec' command should never have been added to the
QEMU guest agent, for precisely this reason that it makes it
impractical to put any meaningful security controls around it.
Likewise the commands which allow arbitrary file read/write.

QEMU guest agent should focus on specific targetted tasks
with dedicated commands.

NB: in RHEL we disable all those unconfinable commands.


If users want to support an ability to have arbitrary command
execution, then that should be done with SSH over VSock, where
the guest owner can choose whether to require authentication
first or not, and use SSH authorized_keys if desired to limit
what commands can be run for a given recorded key.

These days systemd installs magic to allow SSH'ing directly
to a guest using VSOCK addresses, and libvirt further
enhances that to allow SSH'ing to a named VM.


We're repeatedly getting patches to add more functionality to
the "exec" command and they all reflect the fact that what
users need is a general purpose shell with vastly more
functionality than the 'exec' command - authentication,
and authorization being top of the list. IMHO this is not
something QEMU should be trying to address.

> 
> Signed-off-by: Cathy Hu <cahu@suse.de>
> ---
>  qga/commands.c               | 13 +++++++++++++
>  qga/meson.build              |  7 +++++++
>  qga/qemu-ga-selinux-helper.c | 17 +++++++++++++++++
>  3 files changed, 37 insertions(+)
>  create mode 100644 qga/qemu-ga-selinux-helper.c
> 
> diff --git a/qga/commands.c b/qga/commands.c
> index 5f20af25d3..29c092630b 100644
> --- a/qga/commands.c
> +++ b/qga/commands.c
> @@ -30,6 +30,10 @@
>   */
>  #define GUEST_FILE_READ_COUNT_MAX (48 * MiB)
>  
> +#ifdef CONFIG_SELINUX
> +#define GUEST_EXEC_SELINUX_HELPER CONFIG_QEMU_HELPERDIR "/qemu-ga-selinux-helper"
> +#endif
> +
>  /* Note: in some situations, like with the fsfreeze, logging may be
>   * temporarily disabled. if it is necessary that a command be able
>   * to log for accounting purposes, check ga_logging_enabled() beforehand.
> @@ -418,6 +422,9 @@ GuestExec *qmp_guest_exec(const char *path,
>      GuestExecInfo *gei;
>      char **argv, **envp;
>      strList arglist;
> +#ifdef CONFIG_SELINUX
> +    strList helper_arg;
> +#endif
>      gboolean ret;
>      GError *gerr = NULL;
>      gint in_fd, out_fd, err_fd;
> @@ -439,7 +446,13 @@ GuestExec *qmp_guest_exec(const char *path,
>          }
>      }
>  
> +#ifdef CONFIG_SELINUX
> +    helper_arg.value = get_relocated_path(GUEST_EXEC_SELINUX_HELPER);
> +    helper_arg.next = &arglist;
> +    argv = guest_exec_get_args(&helper_arg, true);
> +#else
>      argv = guest_exec_get_args(&arglist, true);
> +#endif
>      envp = has_env ? guest_exec_get_args(env, false) : NULL;
>  
>      flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD |
> diff --git a/qga/meson.build b/qga/meson.build
> index 89a4a8f713..61f60fba26 100644
> --- a/qga/meson.build
> +++ b/qga/meson.build
> @@ -125,6 +125,13 @@ qga = executable('qemu-ga', qga_ss.sources() + qga_objs,
>                   install: true)
>  all_qga += qga
>  
> +if selinux.found()
> +  qga_selinux_helper = executable('qemu-ga-selinux-helper', files('qemu-ga-selinux-helper.c'),
> +             install: true,
> +             install_dir: get_option('libexecdir'))
> +  all_qga += qga_selinux_helper
> +endif
> +
>  if host_os == 'windows'
>    qemu_ga_msi_arch = {
>      'x86': ['-D', 'Arch=32'],
> diff --git a/qga/qemu-ga-selinux-helper.c b/qga/qemu-ga-selinux-helper.c
> new file mode 100644
> index 0000000000..a184e74ede
> --- /dev/null
> +++ b/qga/qemu-ga-selinux-helper.c
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +#include <stdio.h>
> +#include <glib.h>
> +
> +int main(int argc, char **argv)
> +{
> +    if (argc < 2) {
> +        return EXIT_FAILURE;
> +    }
> +
> +    execvp(argv[1], argv + 1);
> +
> +    int err = errno;
> +    fprintf(stderr, "%s: %s\n", argv[1], strerror(err));
> +
> +    exit(EXIT_FAILURE);
> +}
> -- 
> 2.53.0
> 
> 

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450)
  2026-03-27 14:33 ` Daniel P. Berrangé
@ 2026-03-27 21:33   ` Kostiantyn Kostiuk
  2026-04-14 16:51   ` Martin Wilck
  1 sibling, 0 replies; 7+ messages in thread
From: Kostiantyn Kostiuk @ 2026-03-27 21:33 UTC (permalink / raw)
  To: Cathy Hu
  Cc: Daniel P. Berrangé, qemu-devel, Cathy Hu, Fabiano Rosas,
	KVM Bugs, Yan Vugenfirer

[-- Attachment #1: Type: text/plain, Size: 7879 bytes --]

I totally agree with Daniel.

We have a lot of questions or feature requests related to exec/files
commands to add allow/deny lists, etc.
There is no good solution and in 2026 this is not looks like a good feature
at all.

Your patch is more like a workaround for Linux-only and doesn't improve
Windows security.

As Daniel already mentioned, in RHEL, we disable all these unconfineable
commands.
Also, SSH over VSock is available for both Linux and Windows.

I think we should start a discussion about marking exec/files commands as
deprecated
and remove it at some point.
Now better communication method exists.

On Fri, Mar 27, 2026 at 4:35 PM Daniel P. Berrangé <berrange@redhat.com>
wrote:

> On Fri, Mar 27, 2026 at 11:25:19AM +0100, Cathy Hu wrote:
> > From: Cathy Hu <cahu@suse.de>
> >
> > Problem:
> >
> > ATM the QEMU Guest Agent and SELinux are not working together properly.
> > The fedora (and therefor also the openSUSE) policy confine the
> qemu-guest-agent
> > service in the domain `qemu_ga_t`. That means, qemu-guest-agent
> > is only allowed to do what the policy says.
> >
> > However, the `guest-exec` command allows arbitrary execution
> > of code from a privileged service, which conflicts with the
> > notion of SELinux confinement.
> >
> > ATM, the policy allows only some accesses that are used
> > by other qemu-guest-agent commands.
> > That means, the qemu-guest-agent fails sporadically, depending
> > on what is allowed for other commands.
> > However, `guest-exec` would need to allow everything.
> >
> > see https://bugzilla.suse.com/show_bug.cgi?id=1237450
> >
> > Solution:
> >
> > This is not an great solution, but it works like this:
> > We add a "wrapper" which is executed instead of the program
> > that is called via `guest-exec`. The "wrapper" just
> > re-executes the command given by `guest-exec`.
> > This way, on the SELinux policy side we can give that
> > wrapper executable a label on the file system.
> > With that label, we can transition into a more broader
> > unconfined domain _and_ toggle that transition with a
> > SELinux boolean. That would make `guest-exec`
> > consistently allowed to execute or not by policy.
> >
> > This needs a change on the SELinux policy side to
> > accompany this with:
> > https://github.com/fedora-selinux/selinux-policy/pull/3122
> >
> > What other options have been tried unsuccessfully:
> >
> > - Fixing via SELinux policy: It is not possible for
> >   one domain to have different permissions depending on
> >   code path. It is also not possible to toggle the permissive
> >   state via a SELinux boolean, so users would need
> >   to add it via semanage.
> > - Setting the domain of the executed commands directly
> >   to a broader domain with setcon/setexeccon.
> >   The SELinux kernel does not allow to spawn a process
> >   directly with those that has broader privileges than the parent.
> >
> > What other options are there to solve this issue:
> >
> > - Making the qemu-guest-agent unconfined by default
> > - Document the workaround to use semanage to make the domain permissive
> >   if `exec-guest` is needed as works as intended and ignore the problem
>
> IMHO, the 'exec' command should never have been added to the
> QEMU guest agent, for precisely this reason that it makes it
> impractical to put any meaningful security controls around it.
> Likewise the commands which allow arbitrary file read/write.
>
> QEMU guest agent should focus on specific targetted tasks
> with dedicated commands.
>
> NB: in RHEL we disable all those unconfinable commands.
>
>
> If users want to support an ability to have arbitrary command
> execution, then that should be done with SSH over VSock, where
> the guest owner can choose whether to require authentication
> first or not, and use SSH authorized_keys if desired to limit
> what commands can be run for a given recorded key.
>
> These days systemd installs magic to allow SSH'ing directly
> to a guest using VSOCK addresses, and libvirt further
> enhances that to allow SSH'ing to a named VM.
>
>
> We're repeatedly getting patches to add more functionality to
> the "exec" command and they all reflect the fact that what
> users need is a general purpose shell with vastly more
> functionality than the 'exec' command - authentication,
> and authorization being top of the list. IMHO this is not
> something QEMU should be trying to address.
>
> >
> > Signed-off-by: Cathy Hu <cahu@suse.de>
> > ---
> >  qga/commands.c               | 13 +++++++++++++
> >  qga/meson.build              |  7 +++++++
> >  qga/qemu-ga-selinux-helper.c | 17 +++++++++++++++++
> >  3 files changed, 37 insertions(+)
> >  create mode 100644 qga/qemu-ga-selinux-helper.c
> >
> > diff --git a/qga/commands.c b/qga/commands.c
> > index 5f20af25d3..29c092630b 100644
> > --- a/qga/commands.c
> > +++ b/qga/commands.c
> > @@ -30,6 +30,10 @@
> >   */
> >  #define GUEST_FILE_READ_COUNT_MAX (48 * MiB)
> >
> > +#ifdef CONFIG_SELINUX
> > +#define GUEST_EXEC_SELINUX_HELPER CONFIG_QEMU_HELPERDIR
> "/qemu-ga-selinux-helper"
> > +#endif
> > +
> >  /* Note: in some situations, like with the fsfreeze, logging may be
> >   * temporarily disabled. if it is necessary that a command be able
> >   * to log for accounting purposes, check ga_logging_enabled()
> beforehand.
> > @@ -418,6 +422,9 @@ GuestExec *qmp_guest_exec(const char *path,
> >      GuestExecInfo *gei;
> >      char **argv, **envp;
> >      strList arglist;
> > +#ifdef CONFIG_SELINUX
> > +    strList helper_arg;
> > +#endif
> >      gboolean ret;
> >      GError *gerr = NULL;
> >      gint in_fd, out_fd, err_fd;
> > @@ -439,7 +446,13 @@ GuestExec *qmp_guest_exec(const char *path,
> >          }
> >      }
> >
> > +#ifdef CONFIG_SELINUX
> > +    helper_arg.value = get_relocated_path(GUEST_EXEC_SELINUX_HELPER);
> > +    helper_arg.next = &arglist;
> > +    argv = guest_exec_get_args(&helper_arg, true);
> > +#else
> >      argv = guest_exec_get_args(&arglist, true);
> > +#endif
> >      envp = has_env ? guest_exec_get_args(env, false) : NULL;
> >
> >      flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD |
> > diff --git a/qga/meson.build b/qga/meson.build
> > index 89a4a8f713..61f60fba26 100644
> > --- a/qga/meson.build
> > +++ b/qga/meson.build
> > @@ -125,6 +125,13 @@ qga = executable('qemu-ga', qga_ss.sources() +
> qga_objs,
> >                   install: true)
> >  all_qga += qga
> >
> > +if selinux.found()
> > +  qga_selinux_helper = executable('qemu-ga-selinux-helper',
> files('qemu-ga-selinux-helper.c'),
> > +             install: true,
> > +             install_dir: get_option('libexecdir'))
> > +  all_qga += qga_selinux_helper
> > +endif
> > +
> >  if host_os == 'windows'
> >    qemu_ga_msi_arch = {
> >      'x86': ['-D', 'Arch=32'],
> > diff --git a/qga/qemu-ga-selinux-helper.c b/qga/qemu-ga-selinux-helper.c
> > new file mode 100644
> > index 0000000000..a184e74ede
> > --- /dev/null
> > +++ b/qga/qemu-ga-selinux-helper.c
> > @@ -0,0 +1,17 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +#include <stdio.h>
> > +#include <glib.h>
> > +
> > +int main(int argc, char **argv)
> > +{
> > +    if (argc < 2) {
> > +        return EXIT_FAILURE;
> > +    }
> > +
> > +    execvp(argv[1], argv + 1);
> > +
> > +    int err = errno;
> > +    fprintf(stderr, "%s: %s\n", argv[1], strerror(err));
> > +
> > +    exit(EXIT_FAILURE);
> > +}
> > --
> > 2.53.0
> >
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
> |: https://libvirt.org          ~~          https://entangle-photo.org :|
> |: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
>
>
>

[-- Attachment #2: Type: text/html, Size: 10247 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450)
  2026-03-27 14:33 ` Daniel P. Berrangé
  2026-03-27 21:33   ` Kostiantyn Kostiuk
@ 2026-04-14 16:51   ` Martin Wilck
  2026-04-14 17:00     ` Daniel P. Berrangé
  1 sibling, 1 reply; 7+ messages in thread
From: Martin Wilck @ 2026-04-14 16:51 UTC (permalink / raw)
  To: Daniel P. Berrangé, Cathy Hu
  Cc: qemu-devel, Cathy Hu, Fabiano Rosas, KVM Bugs

On Fri, 2026-03-27 at 14:33 +0000, Daniel P. Berrangé wrote:
> On Fri, Mar 27, 2026 at 11:25:19AM +0100, Cathy Hu wrote:
> > From: Cathy Hu <cahu@suse.de>
> > 
> > Problem:
> > 
> > ATM the QEMU Guest Agent and SELinux are not working together
> > properly.
> > The fedora (and therefor also the openSUSE) policy confine the
> > qemu-guest-agent
> > service in the domain `qemu_ga_t`. That means, qemu-guest-agent
> > is only allowed to do what the policy says.
> > 
> > However, the `guest-exec` command allows arbitrary execution
> > of code from a privileged service, which conflicts with the
> > notion of SELinux confinement.
> > 
> > ATM, the policy allows only some accesses that are used
> > by other qemu-guest-agent commands.
> > That means, the qemu-guest-agent fails sporadically, depending
> > on what is allowed for other commands.
> > However, `guest-exec` would need to allow everything.
> > 
> > see https://bugzilla.suse.com/show_bug.cgi?id=1237450
> > 
> > Solution:
> > 
> > This is not an great solution, but it works like this:
> > We add a "wrapper" which is executed instead of the program
> > that is called via `guest-exec`. The "wrapper" just
> > re-executes the command given by `guest-exec`.
> > This way, on the SELinux policy side we can give that
> > wrapper executable a label on the file system.
> > With that label, we can transition into a more broader
> > unconfined domain _and_ toggle that transition with a
> > SELinux boolean. That would make `guest-exec`
> > consistently allowed to execute or not by policy.
> > 
> > This needs a change on the SELinux policy side to
> > accompany this with:
> > https://github.com/fedora-selinux/selinux-policy/pull/3122
> > 
> > What other options have been tried unsuccessfully:
> > 
> > - Fixing via SELinux policy: It is not possible for
> >   one domain to have different permissions depending on
> >   code path. It is also not possible to toggle the permissive
> >   state via a SELinux boolean, so users would need
> >   to add it via semanage.
> > - Setting the domain of the executed commands directly
> >   to a broader domain with setcon/setexeccon.
> >   The SELinux kernel does not allow to spawn a process
> >   directly with those that has broader privileges than the parent.
> > 
> > What other options are there to solve this issue:
> > 
> > - Making the qemu-guest-agent unconfined by default
> > - Document the workaround to use semanage to make the domain
> > permissive
> >   if `exec-guest` is needed as works as intended and ignore the
> > problem
> 
> IMHO, the 'exec' command should never have been added to the
> QEMU guest agent, for precisely this reason that it makes it
> impractical to put any meaningful security controls around it.
> Likewise the commands which allow arbitrary file read/write.
> 
> QEMU guest agent should focus on specific targetted tasks
> with dedicated commands.
> 
> NB: in RHEL we disable all those unconfinable commands.
> 

Downstream bug reporter here. My use case, for which Cathy has come up
with the solution proposed, was to be able to run the ansible libvirt
connection plugin to connect to a freshly installed VM before sshd was
actually configured on the VM, or on a VM that didn't allow ssh access
at all.

My thinking was that the access control was done by libvirt in this
case. The user running ansible would either need to have access to
qemu:///system, or to some remote libvirt server via libvirt's access
controls (in my case, ssh). Users with this permission level would be
able to pause, hard-reset, or destroy the VM in question, so I was
thinking that being able to execute arbitrary commands inside the VM
was not that problematic. But I may be overlooking something, of
course.

> If users want to support an ability to have arbitrary command
> execution, then that should be done with SSH over VSock, where
> the guest owner can choose whether to require authentication
> first or not, and use SSH authorized_keys if desired to limit
> what commands can be run for a given recorded key.
> 
> These days systemd installs magic to allow SSH'ing directly
> to a guest using VSOCK addresses, and libvirt further
> enhances that to allow SSH'ing to a named VM.

Thanks, I wasn't aware of this feature so far. I suppose you're
referring to https://libvirt.org/ssh-proxy.html. I'll need to
experiment with it. IIUC this works for local libvirt connections only?
If that's the case, it wouldn't be a full replacement for qemu-agent
based access, which I've found to be particularly handy for remote
libvirt instances.

Regards,
Martin


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450)
  2026-04-14 16:51   ` Martin Wilck
@ 2026-04-14 17:00     ` Daniel P. Berrangé
  2026-04-14 17:13       ` Martin Wilck
  0 siblings, 1 reply; 7+ messages in thread
From: Daniel P. Berrangé @ 2026-04-14 17:00 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Cathy Hu, qemu-devel, Cathy Hu, Fabiano Rosas, KVM Bugs

On Tue, Apr 14, 2026 at 06:51:12PM +0200, Martin Wilck wrote:
> On Fri, 2026-03-27 at 14:33 +0000, Daniel P. Berrangé wrote:
> > On Fri, Mar 27, 2026 at 11:25:19AM +0100, Cathy Hu wrote:
> > > From: Cathy Hu <cahu@suse.de>
> > > 
> > > Problem:
> > > 
> > > ATM the QEMU Guest Agent and SELinux are not working together
> > > properly.
> > > The fedora (and therefor also the openSUSE) policy confine the
> > > qemu-guest-agent
> > > service in the domain `qemu_ga_t`. That means, qemu-guest-agent
> > > is only allowed to do what the policy says.
> > > 
> > > However, the `guest-exec` command allows arbitrary execution
> > > of code from a privileged service, which conflicts with the
> > > notion of SELinux confinement.
> > > 
> > > ATM, the policy allows only some accesses that are used
> > > by other qemu-guest-agent commands.
> > > That means, the qemu-guest-agent fails sporadically, depending
> > > on what is allowed for other commands.
> > > However, `guest-exec` would need to allow everything.
> > > 
> > > see https://bugzilla.suse.com/show_bug.cgi?id=1237450
> > > 
> > > Solution:
> > > 
> > > This is not an great solution, but it works like this:
> > > We add a "wrapper" which is executed instead of the program
> > > that is called via `guest-exec`. The "wrapper" just
> > > re-executes the command given by `guest-exec`.
> > > This way, on the SELinux policy side we can give that
> > > wrapper executable a label on the file system.
> > > With that label, we can transition into a more broader
> > > unconfined domain _and_ toggle that transition with a
> > > SELinux boolean. That would make `guest-exec`
> > > consistently allowed to execute or not by policy.
> > > 
> > > This needs a change on the SELinux policy side to
> > > accompany this with:
> > > https://github.com/fedora-selinux/selinux-policy/pull/3122
> > > 
> > > What other options have been tried unsuccessfully:
> > > 
> > > - Fixing via SELinux policy: It is not possible for
> > >   one domain to have different permissions depending on
> > >   code path. It is also not possible to toggle the permissive
> > >   state via a SELinux boolean, so users would need
> > >   to add it via semanage.
> > > - Setting the domain of the executed commands directly
> > >   to a broader domain with setcon/setexeccon.
> > >   The SELinux kernel does not allow to spawn a process
> > >   directly with those that has broader privileges than the parent.
> > > 
> > > What other options are there to solve this issue:
> > > 
> > > - Making the qemu-guest-agent unconfined by default
> > > - Document the workaround to use semanage to make the domain
> > > permissive
> > >   if `exec-guest` is needed as works as intended and ignore the
> > > problem
> > 
> > IMHO, the 'exec' command should never have been added to the
> > QEMU guest agent, for precisely this reason that it makes it
> > impractical to put any meaningful security controls around it.
> > Likewise the commands which allow arbitrary file read/write.
> > 
> > QEMU guest agent should focus on specific targetted tasks
> > with dedicated commands.
> > 
> > NB: in RHEL we disable all those unconfinable commands.
> 
> Downstream bug reporter here. My use case, for which Cathy has come up
> with the solution proposed, was to be able to run the ansible libvirt
> connection plugin to connect to a freshly installed VM before sshd was
> actually configured on the VM, or on a VM that didn't allow ssh access
> at all.
> 
> My thinking was that the access control was done by libvirt in this
> case. The user running ansible would either need to have access to
> qemu:///system, or to some remote libvirt server via libvirt's access
> controls (in my case, ssh). Users with this permission level would be
> able to pause, hard-reset, or destroy the VM in question, so I was
> thinking that being able to execute arbitrary commands inside the VM
> was not that problematic. But I may be overlooking something, of
> course.

Yes, with traditional virtualization, if you have privileged
access to the host OS, then the guest has no real protection.

None the less in very many scenarios, the VM user broadly
considers the hypervisor admin to be untrusted. Even if the
technology can't enforce protection against a host admin,
the guest doesn't have to open the front door and welcome
them in by opening "guest-exec" command.

With confidential virtualization, the host OS is generally 
not supposed to have any unsecured access to the guest. For
this the intent is to disable the majority of guest agent
commands which would compromise guest confidentiality
by the host.


> > If users want to support an ability to have arbitrary command
> > execution, then that should be done with SSH over VSock, where
> > the guest owner can choose whether to require authentication
> > first or not, and use SSH authorized_keys if desired to limit
> > what commands can be run for a given recorded key.
> > 
> > These days systemd installs magic to allow SSH'ing directly
> > to a guest using VSOCK addresses, and libvirt further
> > enhances that to allow SSH'ing to a named VM.
> 
> Thanks, I wasn't aware of this feature so far. I suppose you're
> referring to https://libvirt.org/ssh-proxy.html. I'll need to
> experiment with it. IIUC this works for local libvirt connections only?

Yes, vsock is exposed to the local host.

> If that's the case, it wouldn't be a full replacement for qemu-agent
> based access, which I've found to be particularly handy for remote
> libvirt instances.

Since libvirt doesn't expose guest-execu either, I presume you're
referring to libvirt's support for agent command passthrough.

One alternative for off-node secure access is to use SSH + socat
to access the vsock channel.

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450)
  2026-04-14 17:00     ` Daniel P. Berrangé
@ 2026-04-14 17:13       ` Martin Wilck
  2026-04-14 17:46         ` Daniel P. Berrangé
  0 siblings, 1 reply; 7+ messages in thread
From: Martin Wilck @ 2026-04-14 17:13 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: Cathy Hu, qemu-devel, Cathy Hu, Fabiano Rosas

On Tue, 2026-04-14 at 18:00 +0100, Daniel P. Berrangé wrote:
> On Tue, Apr 14, 2026 at 06:51:12PM +0200, Martin Wilck wrote:
> 
> 
> > > If users want to support an ability to have arbitrary command
> > > execution, then that should be done with SSH over VSock, where
> > > the guest owner can choose whether to require authentication
> > > first or not, and use SSH authorized_keys if desired to limit
> > > what commands can be run for a given recorded key.
> > > 
> > > These days systemd installs magic to allow SSH'ing directly
> > > to a guest using VSOCK addresses, and libvirt further
> > > enhances that to allow SSH'ing to a named VM.
> > 
> > Thanks, I wasn't aware of this feature so far. I suppose you're
> > referring to https://libvirt.org/ssh-proxy.html. I'll need to
> > experiment with it. IIUC this works for local libvirt connections
> > only?
> 
> Yes, vsock is exposed to the local host.

And it can't / won't be implemented for remote hosts?

Martin


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450)
  2026-04-14 17:13       ` Martin Wilck
@ 2026-04-14 17:46         ` Daniel P. Berrangé
  0 siblings, 0 replies; 7+ messages in thread
From: Daniel P. Berrangé @ 2026-04-14 17:46 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Cathy Hu, qemu-devel, Cathy Hu, Fabiano Rosas

On Tue, Apr 14, 2026 at 07:13:14PM +0200, Martin Wilck wrote:
> On Tue, 2026-04-14 at 18:00 +0100, Daniel P. Berrangé wrote:
> > On Tue, Apr 14, 2026 at 06:51:12PM +0200, Martin Wilck wrote:
> > 
> > 
> > > > If users want to support an ability to have arbitrary command
> > > > execution, then that should be done with SSH over VSock, where
> > > > the guest owner can choose whether to require authentication
> > > > first or not, and use SSH authorized_keys if desired to limit
> > > > what commands can be run for a given recorded key.
> > > > 
> > > > These days systemd installs magic to allow SSH'ing directly
> > > > to a guest using VSOCK addresses, and libvirt further
> > > > enhances that to allow SSH'ing to a named VM.
> > > 
> > > Thanks, I wasn't aware of this feature so far. I suppose you're
> > > referring to https://libvirt.org/ssh-proxy.html. I'll need to
> > > experiment with it. IIUC this works for local libvirt connections
> > > only?
> > 
> > Yes, vsock is exposed to the local host.
> 
> And it can't / won't be implemented for remote hosts?

That doesn't make sense conceptually. Think of VSOCK as the equivalent
of a UNIX domain socket, but between host & guest.  If you want off
node access, then IP sockets are what you want, either directly from
the guest, or tunnelled to VSOCK via the host.

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-04-14 17:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-27 10:25 [PATCH RFC] qga: Add selinux-helper for guest-exec subcommand (bsc#1237450) Cathy Hu
2026-03-27 14:33 ` Daniel P. Berrangé
2026-03-27 21:33   ` Kostiantyn Kostiuk
2026-04-14 16:51   ` Martin Wilck
2026-04-14 17:00     ` Daniel P. Berrangé
2026-04-14 17:13       ` Martin Wilck
2026-04-14 17:46         ` Daniel P. Berrangé

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.