I met a problem that container blocked by seteuid/setegid
which is call in lxcContainerSetID on UP system and libvirt
compiled with --with-fuse=yes.
I looked into the glibc's codes, and found setxid in glibc
calls futex() to wait for other threads to change their
setxid_futex to 0(see setxid_mark_thread in glibc).
since the process created by clone system call will not
share the memory with the other threads and the context
of memory doesn't changed until we call execl.(COW)
So if the process which created by clone is called before
fuse thread being stated, the new setxid_futex of fuse
thread will not be saw in this process, it will be blocked
forever.
This patch makes sure the cloned process calls setxid first,
and then the lxc controller creates fuse thread.
Signed-off-by: Gao feng <gaofeng(a)cn.fujitsu.com>
---
src/lxc/lxc_container.c | 29 +++++++++++++++--------------
src/lxc/lxc_controller.c | 10 +++++++++-
src/lxc/lxc_fuse.c | 21 +++++++++++++++------
src/lxc/lxc_fuse.h | 1 +
4 files changed, 40 insertions(+), 21 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index c000a82..27bdcc0 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -1844,9 +1844,24 @@ static int lxcContainerChild(void *data)
cmd = lxcContainerBuildInitCmd(vmDef);
virCommandWriteArgLog(cmd, 1);
+ /* call setxid before libvirt controller creates fuse thread. */
if (lxcContainerSetID(vmDef) < 0)
goto cleanup;
+ /* rename and enable interfaces */
+ if (lxcContainerRenameAndEnableInterfaces(!!(vmDef->features &
+ (1 <<
VIR_DOMAIN_FEATURE_PRIVNET)),
+ argv->nveths,
+ argv->veths) < 0) {
+ goto cleanup;
+ }
+
+ if (lxcContainerSendContinue(argv->handshakefd) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Failed to send continue signal to
controller"));
+ goto cleanup;
+ }
+
root = virDomainGetRootFilesystem(vmDef);
if (argv->nttyPaths) {
@@ -1886,24 +1901,10 @@ static int lxcContainerChild(void *data)
goto cleanup;
}
- /* rename and enable interfaces */
- if (lxcContainerRenameAndEnableInterfaces(!!(vmDef->features &
- (1 <<
VIR_DOMAIN_FEATURE_PRIVNET)),
- argv->nveths,
- argv->veths) < 0) {
- goto cleanup;
- }
-
/* drop a set of root capabilities */
if (lxcContainerDropCapabilities(!!hasReboot) < 0)
goto cleanup;
- if (lxcContainerSendContinue(argv->handshakefd) < 0) {
- virReportSystemError(errno, "%s",
- _("Failed to send continue signal to
controller"));
- goto cleanup;
- }
-
VIR_DEBUG("Setting up security labeling");
if (virSecurityManagerSetProcessLabel(argv->securityDriver, vmDef) < 0)
goto cleanup;
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index c8f68c0..5d1ec49 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1981,6 +1981,12 @@ virLXCControllerSetupFuse(virLXCControllerPtr ctrl)
}
static int
+virLXCControllerStartFuse(virLXCControllerPtr ctrl)
+{
+ return lxcStartFuse(ctrl->fuse);
+}
+
+static int
virLXCControllerSetupConsoles(virLXCControllerPtr ctrl,
char **containerTTYPaths)
{
@@ -2197,7 +2203,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
goto cleanup;
}
- /* Now the container is fully setup... */
+ /* container has already called setxid, we can create thread now.*/
+ if (virLXCControllerStartFuse(ctrl) < 0)
+ goto cleanup;
/* ...and reduce our privileges */
if (lxcControllerClearCapabilities() < 0)
diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
index 9d12832..88e122e 100644
--- a/src/lxc/lxc_fuse.c
+++ b/src/lxc/lxc_fuse.c
@@ -322,12 +322,6 @@ int lxcSetupFuse(virLXCFusePtr *f, virDomainDefPtr def)
goto cleanup1;
}
- if (virThreadCreate(&fuse->thread, false, lxcFuseRun,
- (void *)fuse) < 0) {
- lxcFuseDestroy(fuse);
- goto cleanup1;
- }
-
ret = 0;
cleanup:
fuse_opt_free_args(&args);
@@ -341,6 +335,17 @@ cleanup2:
goto cleanup;
}
+int lxcStartFuse(virLXCFusePtr fuse)
+{
+ if (virThreadCreate(&fuse->thread, false, lxcFuseRun,
+ (void *)fuse) < 0) {
+ lxcFuseDestroy(fuse);
+ return -1;
+ }
+
+ return 0;
+}
+
void lxcFreeFuse(virLXCFusePtr *f)
{
virLXCFusePtr fuse = *f;
@@ -364,6 +369,10 @@ int lxcSetupFuse(virLXCFusePtr *f ATTRIBUTE_UNUSED,
return 0;
}
+int lxcStartFuse(virLXCFusePtr f ATTRIBUTE_UNUSED)
+{
+}
+
void lxcFreeFuse(virLXCFusePtr *f ATTRIBUTE_UNUSED)
{
}
diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h
index b3713af..d60492b 100644
--- a/src/lxc/lxc_fuse.h
+++ b/src/lxc/lxc_fuse.h
@@ -58,6 +58,7 @@ struct virLXCFuse {
typedef struct virLXCFuse *virLXCFusePtr;
extern int lxcSetupFuse(virLXCFusePtr *f, virDomainDefPtr def);
+extern int lxcStartFuse(virLXCFusePtr f);
extern void lxcFreeFuse(virLXCFusePtr *f);
#endif /* LXC_FUSE_H */
--
1.8.3.1