diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9c74d35c45..d02d23b359 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2275,6 +2275,7 @@ virProcessGetPids; virProcessGetStartTime; virProcessKill; virProcessKillPainfully; +virProcessNamespaceAvailable; virProcessRunInMountNamespace; virProcessSchedPolicyTypeFromString; virProcessSchedPolicyTypeToString; diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 32c0c3a4a5..e5619b1683 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -2265,7 +2264,7 @@ static int lxcContainerChild(void *data) static int userns_supported(void) { - return lxcContainerAvailable(LXC_CONTAINER_FEATURE_USER) == 0; + return virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_USER) == 0; } static int userns_required(virDomainDefPtr def) @@ -2399,47 +2398,6 @@ int lxcContainerStart(virDomainDefPtr def, return pid; } -ATTRIBUTE_NORETURN static int -lxcContainerDummyChild(void *argv ATTRIBUTE_UNUSED) -{ - _exit(0); -} - -int lxcContainerAvailable(int features) -{ - int flags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS| - CLONE_NEWIPC|SIGCHLD; - int cpid; - char *childStack; - char *stack; - int stacksize = getpagesize() * 4; - - if (features & LXC_CONTAINER_FEATURE_USER) - flags |= CLONE_NEWUSER; - - if (features & LXC_CONTAINER_FEATURE_NET) - flags |= CLONE_NEWNET; - - if (VIR_ALLOC_N(stack, stacksize) < 0) - return -1; - - childStack = stack + stacksize; - - cpid = clone(lxcContainerDummyChild, childStack, flags, NULL); - VIR_FREE(stack); - if (cpid < 0) { - char ebuf[1024] ATTRIBUTE_UNUSED; - VIR_DEBUG("clone call returned %s, container support is not enabled", - virStrerror(errno, ebuf, sizeof(ebuf))); - return -1; - } else if (virProcessWait(cpid, NULL, false) < 0) { - return -1; - } - - VIR_DEBUG("container support is enabled"); - return 0; -} - int lxcContainerChown(virDomainDefPtr def, const char *path) { uid_t uid; diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index 33eaab49c4..e0f508d4a5 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -28,11 +28,6 @@ # include "lxc_domain.h" # include "security/security_manager.h" -enum { - LXC_CONTAINER_FEATURE_NET = (1 << 0), - LXC_CONTAINER_FEATURE_USER = (1 << 1), -}; - # define LXC_DEV_MAJ_MEMORY 1 # define LXC_DEV_MIN_NULL 3 # define LXC_DEV_MIN_ZERO 5 @@ -65,8 +60,6 @@ int lxcContainerStart(virDomainDefPtr def, size_t nttyPaths, char **ttyPaths); -int lxcContainerAvailable(int features); - int lxcContainerSetupHostdevCapsMakePath(const char *dev); virArch lxcContainerGetAlt32bitArch(virArch arch); diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 04a4b8c2a6..a2c1052c65 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1575,7 +1575,7 @@ static int lxcCheckNetNsSupport(void) if (virRun(argv, &ip_rc) < 0 || ip_rc == 255) return 0; - if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0) + if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_NET) < 0) return 0; return 1; @@ -1633,7 +1633,10 @@ static int lxcStateInitialize(bool privileged, } /* Check that this is a container enabled kernel */ - if (lxcContainerAvailable(0) < 0) { + if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_MNT | + VIR_PROCESS_NAMESPACE_PID | + VIR_PROCESS_NAMESPACE_UTS | + VIR_PROCESS_NAMESPACE_IPC) < 0) { VIR_INFO("LXC support not available in this kernel, disabling driver"); return 0; } diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 1ebe863fb5..f5c7ebb96f 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -1183,6 +1183,78 @@ virProcessSetupPrivateMountNS(void) } #endif /* !defined(HAVE_SYS_MOUNT_H) || !defined(HAVE_UNSHARE) */ +#if defined(__linux__) +ATTRIBUTE_NORETURN static int +virProcessDummyChild(void *argv ATTRIBUTE_UNUSED) +{ + _exit(0); +} + +/** + * virProcessNamespaceAvailable: + * @ns: what namespaces to check (bitwise-OR of virProcessNamespaceFlags) + * + * Check if given list of namespaces (@ns) is available. + * If not, appropriate error message is produced. + * + * Returns: 0 on success (all the namespaces from @flags are available), + * -1 on error (with error message reported). + */ +int +virProcessNamespaceAvailable(unsigned int ns) +{ + int flags = 0; + int cpid; + char *childStack; + char *stack; + int stacksize = getpagesize() * 4; + + if (ns & VIR_PROCESS_NAMESPACE_MNT) + flags |= CLONE_NEWNS; + if (ns & VIR_PROCESS_NAMESPACE_IPC) + flags |= CLONE_NEWIPC; + if (ns & VIR_PROCESS_NAMESPACE_NET) + flags |= CLONE_NEWNET; + if (ns & VIR_PROCESS_NAMESPACE_PID) + flags |= CLONE_NEWPID; + if (ns & VIR_PROCESS_NAMESPACE_USER) + flags |= CLONE_NEWUSER; + if (ns & VIR_PROCESS_NAMESPACE_UTS) + flags |= CLONE_NEWUTS; + + /* Signal parent as soon as the child dies. RIP. */ + flags |= SIGCHLD; + + if (VIR_ALLOC_N(stack, stacksize) < 0) + return -1; + + childStack = stack + stacksize; + + cpid = clone(virProcessDummyChild, childStack, flags, NULL); + VIR_FREE(stack); + if (cpid < 0) { + char ebuf[1024] ATTRIBUTE_UNUSED; + VIR_DEBUG("clone call returned %s, container support is not enabled", + virStrerror(errno, ebuf, sizeof(ebuf))); + return -1; + } else if (virProcessWait(cpid, NULL, false) < 0) { + return -1; + } + + VIR_DEBUG("All namespaces (%x) are enabled", ns); + return 0; +} + +#else /* !defined(__linux__) */ + +int +virProcessNamespaceAvailable(unsigned int ns ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Namespaces are not supported on this platform.")); + return -1; +} +#endif /* !defined(__linux__) */ /** * virProcessExitWithStatus: diff --git a/src/util/virprocess.h b/src/util/virprocess.h index c76a1fbc53..3c5a882772 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -95,5 +95,15 @@ int virProcessSetupPrivateMountNS(void); int virProcessSetScheduler(pid_t pid, virProcessSchedPolicy policy, int priority); +typedef enum { + VIR_PROCESS_NAMESPACE_MNT = (1 << 1), + VIR_PROCESS_NAMESPACE_IPC = (1 << 2), + VIR_PROCESS_NAMESPACE_NET = (1 << 3), + VIR_PROCESS_NAMESPACE_PID = (1 << 4), + VIR_PROCESS_NAMESPACE_USER = (1 << 5), + VIR_PROCESS_NAMESPACE_UTS = (1 << 6), +} virProcessNamespaceFlags; + +int virProcessNamespaceAvailable(unsigned int ns); #endif /* __VIR_PROCESS_H__ */