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 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list