[libvirt] [PATCH] qemu: keep capabilities when running QEMU as root
Daniel P. Berrangé
berrange at redhat.com
Wed Dec 11 13:00:39 UTC 2019
ping
On Wed, Dec 04, 2019 at 10:11:47AM +0000, Daniel P. Berrangé wrote:
> When QEMU uid/gid is set to non-root this is pointless as if we just
> used a regular setuid/setgid call, the process will have all its
> capabilities cleared anyway by the kernel.
>
> When QEMU uid/gid is set to root, this is almost (always?) never
> what people actually want. People make QEMU run as root in order
> to access some privileged resource that libvirt doesn't support
> yet and this often requires capabilities. As a result they have
> to go find the qemu.conf param to turn this off. This is not
> viable for libguestfs - they want to control everything via the
> XML security label to request running as root regardless of the
> qemu.conf settings for user/group.
>
> Clearing capabilities was implemented originally because there
> was a proposal in Fedora to change permissions such that root,
> with no capabilities would not be able to compromise the system.
> ie a locked down root account. This never went anywhere though,
> and as a result clearing capabilities when running as root does
> not really get us any security benefit AFAICT. The root user
> can easily do something like create a cronjob, which will then
> faithfully be run with full capabilities, trivially bypassing
> the restriction we place.
>
> IOW, our clearing of capabilities is both useless from a security
> POV, and breaks valid use cases when people need to run as root.
>
> This removes the clear_emulator_capabilities configuration
> option from qemu.conf, and always runs QEMU with capabilities
> when root. The behaviour when non-root is unchanged.
>
> Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
> ---
> docs/drvqemu.html.in | 46 +++++++++++-------------------
> src/qemu/libvirtd_qemu.aug | 8 +++++-
> src/qemu/qemu.conf | 11 -------
> src/qemu/qemu_conf.c | 4 ---
> src/qemu/qemu_conf.h | 1 -
> src/qemu/qemu_domain.c | 3 +-
> src/qemu/qemu_process.c | 5 ----
> src/qemu/test_libvirtd_qemu.aug.in | 1 -
> 8 files changed, 25 insertions(+), 54 deletions(-)
>
> diff --git a/docs/drvqemu.html.in b/docs/drvqemu.html.in
> index 294117ee1f..8beb28655c 100644
> --- a/docs/drvqemu.html.in
> +++ b/docs/drvqemu.html.in
> @@ -187,41 +187,29 @@ chmod o+x /path/to/directory
> </li>
> </ul>
>
> - <h3><a id="securitycap">Linux process capabilities</a></h3>
> -
> <p>
> - The libvirt QEMU driver has a build time option allowing it to use
> - the <a href="http://people.redhat.com/sgrubb/libcap-ng/index.html">libcap-ng</a>
> - library to manage process capabilities. If this build option is
> - enabled, then the QEMU driver will use this to ensure that all
> - process capabilities are dropped before executing a QEMU virtual
> - machine. Process capabilities are what gives the 'root' account
> - its high power, in particular the CAP_DAC_OVERRIDE capability
> - is what allows a process running as 'root' to access files owned
> - by any user.
> + The libvirt maintainers <strong>strongly recommend against</strong>
> + running QEMU as the root user/group. This should not be required
> + in most supported usage scenarios, as libvirt will generally do the
> + right thing to grant QEMU access to files it is permitted to
> + use when it is running non-root.
> </p>
>
> + <h3><a id="securitycap">Linux process capabilities</a></h3>
> +
> <p>
> - If the QEMU driver is configured to run virtual machines as non-root,
> - then they will already lose all their process capabilities at time
> - of startup. The Linux capability feature is thus aimed primarily at
> - the scenario where the QEMU processes are running as root. In this
> - case, before launching a QEMU virtual machine, libvirtd will use
> - libcap-ng APIs to drop all process capabilities. It is important
> - for administrators to note that this implies the QEMU process will
> - <strong>only</strong> be able to access files owned by root, and
> - not files owned by any other user.
> + In versions of libvirt prior to 6.0.0, even if QEMU was configured
> + to run as the root user / group, libvirt would strip all process
> + capabilities. This meant that QEMU could only read/write files
> + owned by root, or with open permissions. In reality, stripping
> + capabilities did not have any security benefit, as it was trivial
> + to get commands to run in another context with full capabilities,
> + for example, by creating a cronjob.
> </p>
> -
> <p>
> - Thus, if a vendor / distributor has configured their libvirt package
> - to run as 'qemu' by default, a number of changes will be required
> - before an administrator can change a host to run guests as root.
> - In particular it will be necessary to change ownership on the
> - directories <code>/var/run/libvirt/qemu/</code>,
> - <code>/var/lib/libvirt/qemu/</code> and
> - <code>/var/cache/libvirt/qemu/</code> back to root, in addition
> - to changing the <code>/etc/libvirt/qemu.conf</code> settings.
> + Thus since 6.0.0, if QEMU is running as root, it will keep all
> + process capabilities. Behaviour when QEMU is running non-root
> + is unchanged, it still has no capabilities.
> </p>
>
> <h3><a id="securityselinux">SELinux basic confinement</a></h3>
> diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
> index 7d7844dc09..86bea2a32a 100644
> --- a/src/qemu/libvirtd_qemu.aug
> +++ b/src/qemu/libvirtd_qemu.aug
> @@ -86,7 +86,6 @@ module Libvirtd_qemu =
> | bool_entry "auto_start_bypass_cache"
>
> let process_entry = str_entry "hugetlbfs_mount"
> - | bool_entry "clear_emulator_capabilities"
> | str_entry "bridge_helper"
> | str_entry "pr_helper"
> | str_entry "slirp_helper"
> @@ -129,6 +128,12 @@ module Libvirtd_qemu =
> let swtpm_entry = str_entry "swtpm_user"
> | str_entry "swtpm_group"
>
> + (* Entries that used to exist in the config which are now
> + * deleted. We keep on parsing them so we don't break
> + * ability to parse old configs after upgrade
> + *)
> + let obsolete_entry = bool_entry "clear_emulator_capabilities"
> +
> let capability_filters_entry = str_array_entry "capability_filters"
>
> (* Each entry in the config is one of the following ... *)
> @@ -153,6 +158,7 @@ module Libvirtd_qemu =
> | nbd_entry
> | swtpm_entry
> | capability_filters_entry
> + | obsolete_entry
>
> let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
> let empty = [ label "#empty" . eol ]
> diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
> index 7a056b037e..b6805ffc41 100644
> --- a/src/qemu/qemu.conf
> +++ b/src/qemu/qemu.conf
> @@ -583,17 +583,6 @@
> #bridge_helper = "/usr/libexec/qemu-bridge-helper"
>
>
> -
> -# If clear_emulator_capabilities is enabled, libvirt will drop all
> -# privileged capabilities of the QEMU/KVM emulator. This is enabled by
> -# default.
> -#
> -# Warning: Disabling this option means that a compromised guest can
> -# exploit the privileges and possibly do damage to the host.
> -#
> -#clear_emulator_capabilities = 1
> -
> -
> # If enabled, libvirt will have QEMU set its process name to
> # "qemu:VM_NAME", where VM_NAME is the name of the VM. The QEMU
> # process will appear as "qemu:VM_NAME" in process listings and
> diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
> index 30637b21ac..0e14d60bc9 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -234,8 +234,6 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
> cfg->prHelperName = g_strdup(QEMU_PR_HELPER);
> cfg->slirpHelperName = g_strdup(QEMU_SLIRP_HELPER);
>
> - cfg->clearEmulatorCapabilities = true;
> -
> cfg->securityDefaultConfined = true;
> cfg->securityRequireConfined = false;
>
> @@ -602,8 +600,6 @@ virQEMUDriverConfigLoadProcessEntry(virQEMUDriverConfigPtr cfg,
> }
> }
>
> - if (virConfGetValueBool(conf, "clear_emulator_capabilities", &cfg->clearEmulatorCapabilities) < 0)
> - return -1;
> if (virConfGetValueString(conf, "bridge_helper", &cfg->bridgeHelperName) < 0)
> return -1;
>
> diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
> index 95b33a1093..a641bbd983 100644
> --- a/src/qemu/qemu_conf.h
> +++ b/src/qemu/qemu_conf.h
> @@ -161,7 +161,6 @@ struct _virQEMUDriverConfig {
> bool relaxedACS;
> bool vncAllowHostAudio;
> bool nogfxAllowHostAudio;
> - bool clearEmulatorCapabilities;
> bool setProcessName;
>
> unsigned int maxProcesses;
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 470d342afc..0dadca4894 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -9345,8 +9345,7 @@ void qemuDomainObjCheckTaint(virQEMUDriverPtr driver,
> bool custom_hypervisor_feat = false;
>
> if (virQEMUDriverIsPrivileged(driver) &&
> - (!cfg->clearEmulatorCapabilities ||
> - cfg->user == 0 ||
> + (cfg->user == 0 ||
> cfg->group == 0))
> qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HIGH_PRIVILEGES, logCtxt);
>
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 75ee3893c6..979ea36f0f 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -6811,11 +6811,6 @@ qemuProcessLaunch(virConnectPtr conn,
> if (qemuDomainCreateNamespace(driver, vm) < 0)
> goto cleanup;
>
> - VIR_DEBUG("Clear emulator capabilities: %d",
> - cfg->clearEmulatorCapabilities);
> - if (cfg->clearEmulatorCapabilities)
> - virCommandClearCaps(cmd);
> -
> VIR_DEBUG("Setting up raw IO");
> if (qemuProcessSetupRawIO(driver, vm, cmd) < 0)
> goto cleanup;
> diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in
> index b9cf8d6688..dd90edf687 100644
> --- a/src/qemu/test_libvirtd_qemu.aug.in
> +++ b/src/qemu/test_libvirtd_qemu.aug.in
> @@ -72,7 +72,6 @@ module Test_libvirtd_qemu =
> { "auto_start_bypass_cache" = "0" }
> { "hugetlbfs_mount" = "/dev/hugepages" }
> { "bridge_helper" = "/usr/libexec/qemu-bridge-helper" }
> -{ "clear_emulator_capabilities" = "1" }
> { "set_process_name" = "1" }
> { "max_processes" = "0" }
> { "max_files" = "0" }
> --
> 2.21.0
>
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