1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-03-07 17:28:15 +00:00

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 <richard@nod.at>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Richard Weinberger 2013-06-07 17:30:09 +01:00 committed by Daniel P. Berrange
parent e463f4de77
commit 68eea85021

View File

@ -22,7 +22,6 @@
#include <config.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
@ -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;