提交 19023562 编写于 作者: D Daniel P. Berrangé

qemu: keep capabilities when running QEMU as root

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.
Reviewed-by: NCole Robinson <crobinso@redhat.com>
Signed-off-by: NDaniel P. Berrangé <berrange@redhat.com>
上级 e8dfddfa
...@@ -187,41 +187,29 @@ chmod o+x /path/to/directory ...@@ -187,41 +187,29 @@ chmod o+x /path/to/directory
</li> </li>
</ul> </ul>
<h3><a id="securitycap">Linux process capabilities</a></h3>
<p> <p>
The libvirt QEMU driver has a build time option allowing it to use The libvirt maintainers <strong>strongly recommend against</strong>
the <a href="http://people.redhat.com/sgrubb/libcap-ng/index.html">libcap-ng</a> running QEMU as the root user/group. This should not be required
library to manage process capabilities. If this build option is in most supported usage scenarios, as libvirt will generally do the
enabled, then the QEMU driver will use this to ensure that all right thing to grant QEMU access to files it is permitted to
process capabilities are dropped before executing a QEMU virtual use when it is running non-root.
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.
</p> </p>
<h3><a id="securitycap">Linux process capabilities</a></h3>
<p> <p>
If the QEMU driver is configured to run virtual machines as non-root, In versions of libvirt prior to 6.0.0, even if QEMU was configured
then they will already lose all their process capabilities at time to run as the root user / group, libvirt would strip all process
of startup. The Linux capability feature is thus aimed primarily at capabilities. This meant that QEMU could only read/write files
the scenario where the QEMU processes are running as root. In this owned by root, or with open permissions. In reality, stripping
case, before launching a QEMU virtual machine, libvirtd will use capabilities did not have any security benefit, as it was trivial
libcap-ng APIs to drop all process capabilities. It is important to get commands to run in another context with full capabilities,
for administrators to note that this implies the QEMU process will for example, by creating a cronjob.
<strong>only</strong> be able to access files owned by root, and
not files owned by any other user.
</p> </p>
<p> <p>
Thus, if a vendor / distributor has configured their libvirt package Thus since 6.0.0, if QEMU is running as root, it will keep all
to run as 'qemu' by default, a number of changes will be required process capabilities. Behaviour when QEMU is running non-root
before an administrator can change a host to run guests as root. is unchanged, it still has no capabilities.
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.
</p> </p>
<h3><a id="securityselinux">SELinux basic confinement</a></h3> <h3><a id="securityselinux">SELinux basic confinement</a></h3>
......
...@@ -86,7 +86,6 @@ module Libvirtd_qemu = ...@@ -86,7 +86,6 @@ module Libvirtd_qemu =
| bool_entry "auto_start_bypass_cache" | bool_entry "auto_start_bypass_cache"
let process_entry = str_entry "hugetlbfs_mount" let process_entry = str_entry "hugetlbfs_mount"
| bool_entry "clear_emulator_capabilities"
| str_entry "bridge_helper" | str_entry "bridge_helper"
| str_entry "pr_helper" | str_entry "pr_helper"
| str_entry "slirp_helper" | str_entry "slirp_helper"
...@@ -129,6 +128,12 @@ module Libvirtd_qemu = ...@@ -129,6 +128,12 @@ module Libvirtd_qemu =
let swtpm_entry = str_entry "swtpm_user" let swtpm_entry = str_entry "swtpm_user"
| str_entry "swtpm_group" | 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" let capability_filters_entry = str_array_entry "capability_filters"
(* Each entry in the config is one of the following ... *) (* Each entry in the config is one of the following ... *)
...@@ -153,6 +158,7 @@ module Libvirtd_qemu = ...@@ -153,6 +158,7 @@ module Libvirtd_qemu =
| nbd_entry | nbd_entry
| swtpm_entry | swtpm_entry
| capability_filters_entry | capability_filters_entry
| obsolete_entry
let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ] let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
let empty = [ label "#empty" . eol ] let empty = [ label "#empty" . eol ]
......
...@@ -583,17 +583,6 @@ ...@@ -583,17 +583,6 @@
#bridge_helper = "/usr/libexec/qemu-bridge-helper" #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 # 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 # "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 # process will appear as "qemu:VM_NAME" in process listings and
......
...@@ -234,8 +234,6 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged) ...@@ -234,8 +234,6 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
cfg->prHelperName = g_strdup(QEMU_PR_HELPER); cfg->prHelperName = g_strdup(QEMU_PR_HELPER);
cfg->slirpHelperName = g_strdup(QEMU_SLIRP_HELPER); cfg->slirpHelperName = g_strdup(QEMU_SLIRP_HELPER);
cfg->clearEmulatorCapabilities = true;
cfg->securityDefaultConfined = true; cfg->securityDefaultConfined = true;
cfg->securityRequireConfined = false; cfg->securityRequireConfined = false;
...@@ -602,8 +600,6 @@ virQEMUDriverConfigLoadProcessEntry(virQEMUDriverConfigPtr cfg, ...@@ -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) if (virConfGetValueString(conf, "bridge_helper", &cfg->bridgeHelperName) < 0)
return -1; return -1;
......
...@@ -161,7 +161,6 @@ struct _virQEMUDriverConfig { ...@@ -161,7 +161,6 @@ struct _virQEMUDriverConfig {
bool relaxedACS; bool relaxedACS;
bool vncAllowHostAudio; bool vncAllowHostAudio;
bool nogfxAllowHostAudio; bool nogfxAllowHostAudio;
bool clearEmulatorCapabilities;
bool setProcessName; bool setProcessName;
unsigned int maxProcesses; unsigned int maxProcesses;
......
...@@ -9512,8 +9512,7 @@ void qemuDomainObjCheckTaint(virQEMUDriverPtr driver, ...@@ -9512,8 +9512,7 @@ void qemuDomainObjCheckTaint(virQEMUDriverPtr driver,
bool custom_hypervisor_feat = false; bool custom_hypervisor_feat = false;
if (virQEMUDriverIsPrivileged(driver) && if (virQEMUDriverIsPrivileged(driver) &&
(!cfg->clearEmulatorCapabilities || (cfg->user == 0 ||
cfg->user == 0 ||
cfg->group == 0)) cfg->group == 0))
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HIGH_PRIVILEGES, logCtxt); qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HIGH_PRIVILEGES, logCtxt);
......
...@@ -6812,11 +6812,6 @@ qemuProcessLaunch(virConnectPtr conn, ...@@ -6812,11 +6812,6 @@ qemuProcessLaunch(virConnectPtr conn,
if (qemuDomainCreateNamespace(driver, vm) < 0) if (qemuDomainCreateNamespace(driver, vm) < 0)
goto cleanup; goto cleanup;
VIR_DEBUG("Clear emulator capabilities: %d",
cfg->clearEmulatorCapabilities);
if (cfg->clearEmulatorCapabilities)
virCommandClearCaps(cmd);
VIR_DEBUG("Setting up raw IO"); VIR_DEBUG("Setting up raw IO");
if (qemuProcessSetupRawIO(driver, vm, cmd) < 0) if (qemuProcessSetupRawIO(driver, vm, cmd) < 0)
goto cleanup; goto cleanup;
......
...@@ -72,7 +72,6 @@ module Test_libvirtd_qemu = ...@@ -72,7 +72,6 @@ module Test_libvirtd_qemu =
{ "auto_start_bypass_cache" = "0" } { "auto_start_bypass_cache" = "0" }
{ "hugetlbfs_mount" = "/dev/hugepages" } { "hugetlbfs_mount" = "/dev/hugepages" }
{ "bridge_helper" = "/usr/libexec/qemu-bridge-helper" } { "bridge_helper" = "/usr/libexec/qemu-bridge-helper" }
{ "clear_emulator_capabilities" = "1" }
{ "set_process_name" = "1" } { "set_process_name" = "1" }
{ "max_processes" = "0" } { "max_processes" = "0" }
{ "max_files" = "0" } { "max_files" = "0" }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册