mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
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>
This commit is contained in:
parent
9117fcb263
commit
b46b1c762a
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user