[libvirt] [PATCHv2 6/7] lxc: add virProcessRunInMountNamespace

Eric Blake eblake at redhat.com
Tue Dec 24 05:55:50 UTC 2013


Implement virProcessRunInMountNamespace, which runs callback of type
virProcessNamespaceCallback in a container namespace.

Idea by Dan Berrange, based on an initial report by Reco
<recoverym4n at gmail.com> at
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=732394

Signed-off-by: Eric Blake <eblake at redhat.com>

---

setns() is a per-thread call.  Would it be any simpler to just
pthread_create() a short-lived helper thread, so that we don't
have to worry about full-blown async-signal safety, and so that
the thread can pass more information back rather than the
limitation of an exit status?
---
 src/libvirt_private.syms |  1 +
 src/util/virprocess.c    | 66 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virprocess.h    | 11 ++++++++
 3 files changed, 78 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 2dbb8f8..e210fd0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1646,6 +1646,7 @@ virProcessGetNamespaces;
 virProcessGetStartTime;
 virProcessKill;
 virProcessKillPainfully;
+virProcessRunInMountNamespace;
 virProcessSetAffinity;
 virProcessSetMaxFiles;
 virProcessSetMaxMemLock;
diff --git a/src/util/virprocess.c b/src/util/virprocess.c
index 5fbed25..c99b75a 100644
--- a/src/util/virprocess.c
+++ b/src/util/virprocess.c
@@ -31,6 +31,7 @@
 # include <sys/resource.h>
 #endif
 #include <sched.h>
+#include <stdlib.h>

 #ifdef __FreeBSD__
 # include <sys/param.h>
@@ -39,6 +40,7 @@
 #endif

 #include "viratomic.h"
+#include "vircommand.h"
 #include "virprocess.h"
 #include "virerror.h"
 #include "viralloc.h"
@@ -850,3 +852,67 @@ int virProcessGetStartTime(pid_t pid,
     return 0;
 }
 #endif
+
+
+#ifdef HAVE_SETNS
+/* Run cb(opaque) in the mount namespace of pid.  Return -1 with error
+ * message raised if we fail to run the child, if the child dies from
+ * a signal, or if the child has status EXIT_CANCELED; otherwise
+ * return the exit status of the child.  */
+int
+virProcessRunInMountNamespace(pid_t pid,
+                              virProcessNamespaceCallback cb,
+                              void *opaque)
+{
+    char *path = NULL;
+    int ret = -1;
+    int cpid = -1;
+    int fd = -1;
+    int status;
+
+    if (virAsprintf(&path, "/proc/%llu/ns/mnt", (unsigned long long)pid) < 0)
+        goto cleanup;
+
+    if ((fd = open(path, O_RDONLY)) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Kernel does not provide mount namespace"));
+        goto cleanup;
+    }
+
+    if ((cpid = virFork() < 0))
+        goto cleanup;
+    if (cpid == 0) {
+        /* child */
+        if (setns(fd, 0) == -1)
+            _exit(EXIT_CANCELED);
+
+        ret = cb(pid, opaque);
+        _exit(ret < 0 ? EXIT_CANCELED : ret);
+    }
+
+    /* parent */
+    if (virProcessWait(cpid, &status) < 0)
+        goto cleanup;
+    if (!WIFEXITED(status) || WEXITSTATUS(status) == EXIT_CANCELED) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("mount namespace callback did not complete normally"));
+        goto cleanup;
+    }
+    ret = WEXITSTATUS(status);
+
+cleanup:
+    VIR_FREE(path);
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
+#else /* !HAVE_SETNS */
+int
+virProcessRunInMountNamespace(pid_t pid ATTRIBUTE_UNUSED,
+                              virProcessNamespaceCallback cb ATTRIBUTE_UNUSED,
+                              void *opaque ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s",
+                         _("Mount namespaces are not available on this platform"));
+    return -1;
+}
+#endif
diff --git a/src/util/virprocess.h b/src/util/virprocess.h
index 9f77bc5..75c7d1b 100644
--- a/src/util/virprocess.h
+++ b/src/util/virprocess.h
@@ -60,4 +60,15 @@ int virProcessSetNamespaces(size_t nfdlist,
 int virProcessSetMaxMemLock(pid_t pid, unsigned long long bytes);
 int virProcessSetMaxProcesses(pid_t pid, unsigned int procs);
 int virProcessSetMaxFiles(pid_t pid, unsigned int files);
+
+/* Callback to run code within the mount namespace tied to the given
+ * pid.  This function must use only async-signal-safe functions, as
+ * it gets run after a fork of a multi-threaded process.  The return
+ * value of this function is passed to _exit(), except that a
+ * negative value is treated as EXIT_CANCELED.  */
+typedef int (*virProcessNamespaceCallback)(pid_t pid, void *opaque);
+
+int virProcessRunInMountNamespace(pid_t pid,
+                                  virProcessNamespaceCallback cb,
+                                  void *opaque);
 #endif /* __VIR_PROCESS_H__ */
-- 
1.8.4.2




More information about the libvir-list mailing list