From 68eea850217e1de921bb1d4bd013aabfac255a23 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 7 Jun 2013 17:30:09 +0100 Subject: [PATCH] Fix ordering of file open in virProcessGetNamespaces virProcessGetNamespaces() opens files in /proc/XXX/ns/ which will later be passed to setns(). We have to make sure that the file descriptors in the array are in the correct order. In particular the 'user' namespace must be first otherwise setns() may fail for other namespaces. The order has been taken from util-linux's sys-utils/nsenter.c Also we must ignore EINVAL in setns() which occurs if the namespace associated with the fd, matches the calling process' current namespace. Signed-off-by: Richard Weinberger Signed-off-by: Daniel P. Berrange --- src/util/virprocess.c | 60 +++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/src/util/virprocess.c b/src/util/virprocess.c index bc028d7081..bf61127eed 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -22,7 +22,6 @@ #include -#include #include #include #include @@ -513,66 +512,43 @@ int virProcessGetNamespaces(pid_t pid, int **fdlist) { int ret = -1; - DIR *dh = NULL; - struct dirent *de; - char *nsdir = NULL; char *nsfile = NULL; - size_t i; + size_t i = 0; + const char *ns[] = { "user", "ipc", "uts", "net", "pid", "mnt" }; *nfdlist = 0; *fdlist = NULL; - if (virAsprintf(&nsdir, "/proc/%llu/ns", - (unsigned long long)pid) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (!(dh = opendir(nsdir))) { - virReportSystemError(errno, - _("Cannot read directory %s"), - nsdir); - goto cleanup; - } - - while ((de = readdir(dh))) { + for (i = 0; i < ARRAY_CARDINALITY(ns); i++) { int fd; - if (de->d_name[0] == '.') - continue; - if (VIR_EXPAND_N(*fdlist, *nfdlist, 1) < 0) { + if (virAsprintf(&nsfile, "/proc/%llu/ns/%s", + (unsigned long long)pid, + ns[i]) < 0) { virReportOOMError(); goto cleanup; } - if (virAsprintf(&nsfile, "%s/%s", nsdir, de->d_name) < 0) { - virReportOOMError(); - goto cleanup; - } + if ((fd = open(nsfile, O_RDWR)) >= 0) { + if (VIR_EXPAND_N(*fdlist, *nfdlist, 1) < 0) { + VIR_FORCE_CLOSE(fd); + virReportOOMError(); + goto cleanup; + } - if ((fd = open(nsfile, O_RDWR)) < 0) { - virReportSystemError(errno, - _("Unable to open %s"), - nsfile); - goto cleanup; + (*fdlist)[(*nfdlist)-1] = fd; } - (*fdlist)[(*nfdlist)-1] = fd; - VIR_FREE(nsfile); } ret = 0; cleanup: - if (dh) - closedir(dh); - VIR_FREE(nsdir); VIR_FREE(nsfile); if (ret < 0) { - for (i = 0; i < *nfdlist; i++) { + for (i = 0; i < *nfdlist; i++) VIR_FORCE_CLOSE((*fdlist)[i]); - } VIR_FREE(*fdlist); } return ret; @@ -590,7 +566,13 @@ int virProcessSetNamespaces(size_t nfdlist, return -1; } for (i = 0; i < nfdlist; i++) { - if (setns(fdlist[i], 0) < 0) { + /* We get EINVAL if new NS is same as the current + * NS, or if the fd namespace doesn't match the + * type passed to setns()'s second param. Since we + * pass 0, we know the EINVAL is harmless + */ + if (setns(fdlist[i], 0) < 0 && + errno != EINVAL) { virReportSystemError(errno, "%s", _("Unable to join domain namespace")); return -1;