This patch updates the LXC driver to make use of libcap-ng for managing process capabilities. Previously Ryota Ozaki had provided code to remove the CAP_BOOT capabilities inside the container, preventing host reboots. In addition to that one, I believe we should be removing ability to load kernel modules, change the system clock and changing audit/MAC. So this patch also clears the following: CAP_SYS_MODULE, /* No kernel module loading */ CAP_SYS_TIME, /* No changing the clock */ CAP_AUDIT_CONTROL, /* No messing with auditing */ CAP_AUDIT_WRITE, /* No messing with auditing */ CAP_MAC_ADMIN, /* No messing with LSM */ CAP_MAC_OVERRIDE, /* No messing with LSM */ We use libcap-ng's capng_updatev/apply functions to remove these from the permitted, inheritable, effective and bounding sets. Then we use capng_lock to set NOROOT and NOROOT_LOCKED in the process securebits to prevent them ever being re-acquired. The other thing I realized is that the 'libvirt_lxc' controller process does not need to keep any capabilities at all once it has spawned the container process, since all its doing is forwarding I/O between 2 open file descripts. So I also clear all capabilities from that. We should probably make it chuid/gid to a non-root user in future too. lxc_container.c | 66 +++++++++++++++++++++++++++++++++++++------------------ lxc_controller.c | 28 +++++++++++++++++++++++ 2 files changed, 73 insertions(+), 21 deletions(-) Regards, Daniel diff -r 7e766489c4a2 src/lxc_container.c --- a/src/lxc_container.c Tue Jun 23 11:13:45 2009 +0100 +++ b/src/lxc_container.c Tue Jun 23 11:54:10 2009 +0100 @@ -41,8 +41,9 @@ /* For MS_MOVE */ #include <linux/fs.h> -#include <sys/prctl.h> -#include <linux/capability.h> +#if HAVE_CAPNG +#include <cap-ng.h> +#endif #include "virterror_internal.h" #include "logging.h" @@ -642,27 +643,50 @@ static int lxcContainerSetupMounts(virDo return lxcContainerSetupExtraMounts(vmDef); } -static int lxcContainerDropCapabilities(virDomainDefPtr vmDef ATTRIBUTE_UNUSED) + +/* + * This is running as the 'init' process insid the container. + * It removes some capabilities that could be dangerous to + * host system, since they are not currently "containerized" + */ +static int lxcContainerDropCapabilities(void) { -#ifdef PR_CAPBSET_DROP - int i; - const struct { - int id; - const char *name; - } caps[] = { -#define ID_STRING(name) name, #name - { ID_STRING(CAP_SYS_BOOT) }, - }; +#if HAVE_CAPNG + int ret; - for (i = 0 ; i < ARRAY_CARDINALITY(caps) ; i++) { - if (prctl(PR_CAPBSET_DROP, caps[i].id, 0, 0, 0)) { - lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to drop %s"), caps[i].name); - return -1; - } + capng_get_caps_process(); + + 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 */ + CAP_AUDIT_WRITE, /* No messing with auditing */ + CAP_MAC_ADMIN, /* No messing with LSM */ + CAP_MAC_OVERRIDE, /* No messing with LSM */ + -1 /* sentinal */)) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to remove capabilities %d"), ret); + return -1; } -#else /* ! PR_CAPBSET_DROP */ - VIR_WARN0(_("failed to drop capabilities PR_CAPBSET_DROP undefined")); + + if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to apply capabilities: %d"), ret); + return -1; + } + + /* Need to prevent them regaining any caps on exec */ + if ((ret = capng_lock()) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to lock capabilities: %d"), ret); + return -1; + } + +#else + VIR_WARN0(_("libcap-ng support not compiled in, unable to clear capabilities")); #endif return 0; } @@ -735,7 +759,7 @@ static int lxcContainerChild( void *data return -1; /* drop a set of root capabilities */ - if (lxcContainerDropCapabilities(vmDef) < 0) + if (lxcContainerDropCapabilities() < 0) return -1; /* this function will only return if an error occured */ diff -r 7e766489c4a2 src/lxc_controller.c --- a/src/lxc_controller.c Tue Jun 23 11:13:45 2009 +0100 +++ b/src/lxc_controller.c Tue Jun 23 11:54:10 2009 +0100 @@ -35,6 +35,10 @@ #include <getopt.h> #include <sys/mount.h> +#if HAVE_CAPNG +#include <cap-ng.h> +#endif + #include "virterror_internal.h" #include "logging.h" #include "util.h" @@ -210,6 +214,25 @@ cleanup: return rc; } + +static int lxcControllerClearCapabilities(void) +{ +#if HAVE_CAPNG + int ret; + + capng_clear(CAPNG_SELECT_BOTH); + + if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to apply capabilities: %d"), ret); + return -1; + } +#else + VIR_WARN0(_("libcap-ng support not compiled in, unable to clear capabilities")); +#endif + return 0; +} + typedef struct _lxcTtyForwardFd_t { int fd; int active; @@ -562,6 +585,11 @@ lxcControllerRun(virDomainDefPtr def, if (lxcContainerSendContinue(control[0]) < 0) goto cleanup; + /* Now the container is running, there's no need for us to keep + any elevated capabilities */ + if (lxcControllerClearCapabilities() < 0) + goto cleanup; + rc = lxcControllerMain(monitor, client, appPty, containerPty); cleanup: -- |: 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