[libvirt] [PATCH 10/11] Allow CAP_SYS_REBOOT on new enough kernels

Jiri Denemark jdenemar at redhat.com
Fri Jul 27 07:59:47 UTC 2012


On Tue, Jul 24, 2012 at 14:22:52 +0100, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange at redhat.com>
> 
> 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 at redhat.com>
> ---
>  src/lxc/lxc_container.c |   88 +++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 85 insertions(+), 3 deletions(-)
> 
> diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
> index c555559..8696e08 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,82 @@ struct __lxc_child_argv {
>  };
>  
>  
> +
> +

Looks like quite a few empty lines here :-)

> +/*
> + * 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("No, containerized reboot support is missing "
> +                  "(kernel probably too old < 3.4)");
> +        return 0;
> +    }
> +
> +    VIR_DEBUG("Yes, there is containerized reboot support");
> +    return 1;
> +}

The last two debug messages are strange, I think
"Containerized reboot support is missing (kernel probably too old < 3.4)" and
"Containerized reboot is supported" would be better.

> +
> +
>  /**
>   * lxcContainerBuildInitCmd:
>   * @vmDef: pointer to vm definition structure
> @@ -1583,7 +1661,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 +1671,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 +1722,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 +1730,9 @@ static int lxcContainerChild( void *data )
>          goto cleanup;
>      }
>  
> +    if ((hasReboot = lxcContainerHasReboot()) < 0)
> +        goto cleanup;
> +
>      cmd = lxcContainerBuildInitCmd(vmDef);
>      virCommandWriteArgLog(cmd, 1);
>  
> @@ -1714,7 +1796,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) {

I trust you the clone() and reboot() magic does the right thing :-) ACK.

Jirka




More information about the libvir-list mailing list