This patch adds a new flag to virExec() called VIR_EXEC_CLEAR_CAPS.
If you set this flag than all capabilities are removed inbetween the
fork() and exec() pair.
It also updates QEMU and UML driver to run their VMs without any privileges.
A mild security benefit for most distros today, but if distros start to
lock down what the unprivileged root user can do, this benefit increases.
It also removes all capabilities from the 'ssh' client spawned by the
remote client, since that shouldn't need any real privileges to open a
tunnel.
Makefile.am | 6 ++++--
qemu_conf.c | 2 +-
qemu_driver.c | 2 +-
remote_internal.c | 6 ++++--
uml_driver.c | 3 ++-
util.c | 33 +++++++++++++++++++++++++++++++++
util.h | 1 +
7 files changed, 46 insertions(+), 7 deletions(-)
Daniel
diff -r 542fbc10a66b src/Makefile.am
--- a/src/Makefile.am Mon Jun 22 19:01:11 2009 +0100
+++ b/src/Makefile.am Mon Jun 22 20:23:18 2009 +0100
@@ -213,6 +213,8 @@ noinst_LTLIBRARIES = libvirt_util.la
libvirt_la_LIBADD = libvirt_util.la
libvirt_util_la_SOURCES = \
$(UTIL_SOURCES)
+libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS)
+libvirt_util_la_LDFLAGS = $(CAPNG_LIBS)
noinst_LTLIBRARIES += libvirt_driver.la
libvirt_la_LIBADD += libvirt_driver.la
@@ -666,9 +668,9 @@ libvirt_lxc_SOURCES = \
$(LXC_CONTROLLER_SOURCES) \
$(UTIL_SOURCES) \
$(DOMAIN_CONF_SOURCES)
-libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS)
+libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS)
libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la
-libvirt_lxc_CFLAGS = $(LIBPARTED_CFLAGS) $(NUMACTL_CFLAGS)
+libvirt_lxc_CFLAGS = $(LIBPARTED_CFLAGS) $(NUMACTL_CFLAGS) $(CAPNG_CFLAGS)
endif
endif
EXTRA_DIST += $(LXC_CONTROLLER_SOURCES)
diff -r 542fbc10a66b src/qemu_conf.c
--- a/src/qemu_conf.c Mon Jun 22 19:01:11 2009 +0100
+++ b/src/qemu_conf.c Mon Jun 22 20:23:18 2009 +0100
@@ -590,7 +590,7 @@ int qemudExtractVersionInfo(const char *
*retversion = 0;
if (virExec(NULL, qemuarg, qemuenv, NULL,
- &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0)
+ &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
return -1;
char *help = NULL;
diff -r 542fbc10a66b src/qemu_driver.c
--- a/src/qemu_driver.c Mon Jun 22 19:01:11 2009 +0100
+++ b/src/qemu_driver.c Mon Jun 22 20:23:18 2009 +0100
@@ -1449,7 +1449,7 @@ static int qemudStartVMDaemon(virConnect
ret = virExecDaemonize(conn, argv, progenv, &keepfd, &child,
stdin_fd, &logfile, &logfile,
- VIR_EXEC_NONBLOCK,
+ VIR_EXEC_NONBLOCK | VIR_EXEC_CLEAR_CAPS,
qemudSecurityHook, &hookData,
pidfile);
VIR_FREE(pidfile);
diff -r 542fbc10a66b src/remote_internal.c
--- a/src/remote_internal.c Mon Jun 22 19:01:11 2009 +0100
+++ b/src/remote_internal.c Mon Jun 22 20:23:18 2009 +0100
@@ -295,7 +295,8 @@ remoteForkDaemon(virConnectPtr conn)
}
if (virExecDaemonize(NULL, daemonargs, NULL, NULL,
- &pid, -1, NULL, NULL, 0,
+ &pid, -1, NULL, NULL,
+ VIR_EXEC_CLEAR_CAPS,
NULL, NULL, NULL) < 0)
return -1;
@@ -749,7 +750,8 @@ doRemoteOpen (virConnectPtr conn,
}
if (virExec(conn, (const char**)cmd_argv, NULL, NULL,
- &pid, sv[1], &(sv[1]), NULL, VIR_EXEC_NONE) < 0)
+ &pid, sv[1], &(sv[1]), NULL,
+ VIR_EXEC_CLEAR_CAPS) < 0)
goto failed;
/* Parent continues here. */
diff -r 542fbc10a66b src/uml_driver.c
--- a/src/uml_driver.c Mon Jun 22 19:01:11 2009 +0100
+++ b/src/uml_driver.c Mon Jun 22 20:23:18 2009 +0100
@@ -850,7 +850,8 @@ static int umlStartVMDaemon(virConnectPt
ret = virExecDaemonize(conn, argv, progenv, &keepfd, &pid,
-1, &logfd, &logfd,
- 0, NULL, NULL, NULL);
+ VIR_EXEC_CLEAR_CAPS,
+ NULL, NULL, NULL);
close(logfd);
for (i = 0 ; argv[i] ; i++)
diff -r 542fbc10a66b src/util.c
--- a/src/util.c Mon Jun 22 19:01:11 2009 +0100
+++ b/src/util.c Mon Jun 22 20:23:18 2009 +0100
@@ -57,6 +57,10 @@
#include <pwd.h>
#include <grp.h>
#endif
+#if HAVE_CAPNG
+#include <cap-ng.h>
+#endif
+
#include "virterror_internal.h"
#include "logging.h"
@@ -265,6 +269,29 @@ int virSetCloseExec(int fd) {
return 0;
}
+
+#if HAVE_CAPNG
+static int virClearCapabilities(void)
+{
+ int ret;
+
+ capng_clear(CAPNG_SELECT_BOTH);
+
+ if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
+ VIR_ERROR("cannot clear process capabilities %d", ret);
+ return -1;
+ }
+
+ return 0;
+}
+#else
+static int virClearCapabilities(void)
+{
+// VIR_WARN0("libcap-ng support not compiled in, unable to clear
capabilities");
+ return 0;
+}
+#endif
+
/*
* @conn Connection to report errors against
* @argv argv to exec
@@ -490,6 +517,12 @@ __virExec(virConnectPtr conn,
if ((hook)(data) != 0)
_exit(1);
+ /* The hook above may need todo something privileged, so
+ * we delay clearing capabilities until now */
+ if ((flags & VIR_EXEC_CLEAR_CAPS) &&
+ virClearCapabilities() < 0)
+ _exit(1);
+
/* Daemonize as late as possible, so the parent process can detect
* the above errors with wait* */
if (flags & VIR_EXEC_DAEMON) {
diff -r 542fbc10a66b src/util.h
--- a/src/util.h Mon Jun 22 19:01:11 2009 +0100
+++ b/src/util.h Mon Jun 22 20:23:18 2009 +0100
@@ -37,6 +37,7 @@ enum {
VIR_EXEC_NONE = 0,
VIR_EXEC_NONBLOCK = (1 << 0),
VIR_EXEC_DAEMON = (1 << 1),
+ VIR_EXEC_CLEAR_CAPS = (1 << 2),
};
int virSetNonBlock(int fd);
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|