Implement virProcessRunInMountNamespace, which runs callback of type virProcessNamespaceCallback in a container namespace. Idea by Dan Berrange, based on an initial report by Reco <recoverym4n@xxxxxxxxx> at http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=732394 Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list