From: "Daniel P. Berrange" <berrange(a)redhat.com>
Given an LXC guest with a root filesystem path of
/export/lxc/roots/helloworld/root
During startup, we will pivot the root filesystem to end up
at
/.oldroot/export/lxc/roots/helloworld/root
We then try to open
/.oldroot/export/lxc/roots/helloworld/root/dev/pts
Now consider if '/export/lxc' is an absolute symlink pointing
to '/media/lxc'. The kernel will try to open
/media/lxc/roots/helloworld/root/dev/pts
whereas it should be trying to open
/.oldroot//media/lxc/roots/helloworld/root/dev/pts
To deal with the fact that the root filesystem can be moved,
we need to resolve symlinks in *any* part of the filesystem
source path.
* src/libvirt_private.syms, src/util/util.c,
src/util/util.h: Add virFileResolveAllLinks to resolve
all symlinks in a path
* src/lxc/lxc_container.c: Resolve all symlinks in filesystem
paths during startup
---
src/libvirt_private.syms | 1 +
src/lxc/lxc_container.c | 23 +++++++++++++++++++++++
src/util/util.c | 43 ++++++++++++++++++++++++++++++++-----------
src/util/util.h | 2 ++
4 files changed, 58 insertions(+), 11 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index faab0e2..f344e73 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1100,6 +1100,7 @@ virFileOpenTty;
virFileReadAll;
virFileReadLimFD;
virFileResolveLink;
+virFileResolveAllLinks;
virFileSanitizePath;
virFileStripSuffix;
virFileUnlock;
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 1e7803a..4e4388b 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -1111,11 +1111,34 @@ static int lxcContainerSetupExtraMounts(virDomainDefPtr vmDef)
return 0;
}
+
+static int lxcContainerResolveSymlinks(virDomainDefPtr vmDef)
+{
+ char *newroot;
+ size_t i;
+
+ for (i = 0 ; i < vmDef->nfss ; i++) {
+ virDomainFSDefPtr fs = vmDef->fss[i];
+ if (virFileResolveAllLinks(fs->src, &newroot) < 0)
+ return -1;
+
+ VIR_DEBUG("Resolved '%s' to %s", fs->src, newroot);
+
+ VIR_FREE(fs->src);
+ fs->src = newroot;
+ }
+
+ return 0;
+}
+
static int lxcContainerSetupMounts(virDomainDefPtr vmDef,
virDomainFSDefPtr root,
char **ttyPaths,
size_t nttyPaths)
{
+ if (lxcContainerResolveSymlinks(vmDef) < 0)
+ return -1;
+
if (root)
return lxcContainerSetupPivotRoot(vmDef, root, ttyPaths, nttyPaths);
else
diff --git a/src/util/util.c b/src/util/util.c
index 6f46d53..8663c4d 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -536,16 +536,10 @@ int virFileLinkPointsTo(const char *checkLink,
-/*
- * Attempt to resolve a symbolic link, returning an
- * absolute path where only the last component is guaranteed
- * not to be a symlink.
- *
- * Return 0 if path was not a symbolic, or the link was
- * resolved. Return -1 with errno set upon error
- */
-int virFileResolveLink(const char *linkpath,
- char **resultpath)
+static int
+virFileResolveLinkHelper(const char *linkpath,
+ bool intermediatePaths,
+ char **resultpath)
{
struct stat st;
@@ -554,7 +548,7 @@ int virFileResolveLink(const char *linkpath,
/* We don't need the full canonicalization of intermediate
* directories, if linkpath is absolute and the basename is
* already a non-symlink. */
- if (IS_ABSOLUTE_FILE_NAME(linkpath)) {
+ if (IS_ABSOLUTE_FILE_NAME(linkpath) && !intermediatePaths) {
if (lstat(linkpath, &st) < 0)
return -1;
@@ -570,6 +564,33 @@ int virFileResolveLink(const char *linkpath,
return *resultpath == NULL ? -1 : 0;
}
+/*
+ * Attempt to resolve a symbolic link, returning an
+ * absolute path where only the last component is guaranteed
+ * not to be a symlink.
+ *
+ * Return 0 if path was not a symbolic, or the link was
+ * resolved. Return -1 with errno set upon error
+ */
+int virFileResolveLink(const char *linkpath,
+ char **resultpath)
+{
+ return virFileResolveLinkHelper(linkpath, false, resultpath);
+}
+
+/*
+ * Attempt to resolve a symbolic link, returning an
+ * absolute path where every component is guaranteed
+ * not to be a symlink.
+ *
+ * Return 0 if path was not a symbolic, or the link was
+ * resolved. Return -1 with errno set upon error
+ */
+int virFileResolveAllLinks(const char *linkpath,
+ char **resultpath)
+{
+ return virFileResolveLinkHelper(linkpath, true, resultpath);
+}
/*
* Check whether the given file is a link.
diff --git a/src/util/util.h b/src/util/util.h
index c9c785b..977ab6c 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -77,6 +77,8 @@ int virFileLinkPointsTo(const char *checkLink,
int virFileResolveLink(const char *linkpath,
char **resultpath) ATTRIBUTE_RETURN_CHECK;
+int virFileResolveAllLinks(const char *linkpath,
+ char **resultpath) ATTRIBUTE_RETURN_CHECK;
int virFileIsLink(const char *linkpath)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
--
1.7.7.5