diff options
author | 2012-07-20 22:16:19 +0100 | |
---|---|---|
committer | 2012-07-30 13:07:45 +0100 | |
commit | b46b1c762a15fa7a85a95669631c4207b67c94bf (patch) | |
tree | be743990957d3e68368696eda7ee8c2583b9728b /src | |
parent | Run an RPC protocol over the LXC controller monitor (diff) | |
download | libvirt-b46b1c762a15fa7a85a95669631c4207b67c94bf.tar.gz libvirt-b46b1c762a15fa7a85a95669631c4207b67c94bf.tar.bz2 libvirt-b46b1c762a15fa7a85a95669631c4207b67c94bf.zip |
Allow CAP_SYS_REBOOT on new enough kernels
Check whether the reboot() system call is virtualized, and if
it is, then allow the container to keep CAP_SYS_REBOOT.
Based on an original patch by Serge Hallyn
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/lxc/lxc_container.c | 86 |
1 files changed, 83 insertions, 3 deletions
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index c555559d6..6043b00bb 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -36,6 +36,8 @@ #include <unistd.h> #include <mntent.h> #include <dirent.h> +#include <sys/reboot.h> +#include <linux/reboot.h> /* Yes, we want linux private one, for _syscall2() macro */ #include <linux/unistd.h> @@ -102,6 +104,80 @@ struct __lxc_child_argv { }; +/* + * reboot(LINUX_REBOOT_CMD_CAD_ON) will return -EINVAL + * in a child pid namespace if container reboot support exists. + * Otherwise, it will either succeed or return -EPERM. + */ +ATTRIBUTE_NORETURN static int +lxcContainerRebootChild(void *argv) +{ + int *cmd = argv; + int ret; + + ret = reboot(*cmd); + if (ret == -1 && errno == EINVAL) + _exit(1); + _exit(0); +} + + +static +int lxcContainerHasReboot(void) +{ + int flags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS| + CLONE_NEWIPC|SIGCHLD; + int cpid; + char *childStack; + char *stack; + char *buf; + int cmd, v; + int status; + char *tmp; + + if (virFileReadAll("/proc/sys/kernel/ctrl-alt-del", 10, &buf) < 0) + return -1; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_i(buf, NULL, 10, &v) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Malformed ctrl-alt-del setting '%s'"), buf); + VIR_FREE(buf); + return -1; + } + VIR_FREE(buf); + cmd = v ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF; + + if (VIR_ALLOC_N(stack, getpagesize() * 4) < 0) { + virReportOOMError(); + return -1; + } + + childStack = stack + (getpagesize() * 4); + + cpid = clone(lxcContainerRebootChild, childStack, flags, &cmd); + VIR_FREE(stack); + if (cpid < 0) { + virReportSystemError(errno, "%s", + _("Unable to clone to check reboot support")); + return -1; + } else if (virPidWait(cpid, &status) < 0) { + return -1; + } + + if (WEXITSTATUS(status) != 1) { + VIR_DEBUG("Containerized reboot support is missing " + "(kernel probably too old < 3.4)"); + return 0; + } + + VIR_DEBUG("Containerized reboot support is available"); + return 1; +} + + /** * lxcContainerBuildInitCmd: * @vmDef: pointer to vm definition structure @@ -1583,7 +1659,7 @@ static int lxcContainerSetupMounts(virDomainDefPtr vmDef, * It removes some capabilities that could be dangerous to * host system, since they are not currently "containerized" */ -static int lxcContainerDropCapabilities(void) +static int lxcContainerDropCapabilities(bool keepReboot) { #if HAVE_CAPNG int ret; @@ -1593,11 +1669,11 @@ static int lxcContainerDropCapabilities(void) if ((ret = capng_updatev(CAPNG_DROP, CAPNG_EFFECTIVE | CAPNG_PERMITTED | CAPNG_INHERITABLE | CAPNG_BOUNDING_SET, - CAP_SYS_BOOT, /* No use of reboot */ CAP_SYS_MODULE, /* No kernel module loading */ CAP_SYS_TIME, /* No changing the clock */ CAP_AUDIT_CONTROL, /* No messing with auditing status */ CAP_MAC_ADMIN, /* No messing with LSM config */ + keepReboot ? -1 : CAP_SYS_BOOT, /* No use of reboot */ -1 /* sentinal */)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to remove capabilities: %d"), ret); @@ -1644,6 +1720,7 @@ static int lxcContainerChild( void *data ) char *ttyPath = NULL; virDomainFSDefPtr root; virCommandPtr cmd = NULL; + int hasReboot; if (NULL == vmDef) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -1651,6 +1728,9 @@ static int lxcContainerChild( void *data ) goto cleanup; } + if ((hasReboot = lxcContainerHasReboot()) < 0) + goto cleanup; + cmd = lxcContainerBuildInitCmd(vmDef); virCommandWriteArgLog(cmd, 1); @@ -1714,7 +1794,7 @@ static int lxcContainerChild( void *data ) } /* drop a set of root capabilities */ - if (lxcContainerDropCapabilities() < 0) + if (lxcContainerDropCapabilities(!!hasReboot) < 0) goto cleanup; if (lxcContainerSendContinue(argv->handshakefd) < 0) { |