[libvirt] [PATCH] Fix startup of LXC containers with filesystems containing symlinks

Daniel P. Berrange berrange at redhat.com
Tue Jan 17 21:40:20 UTC 2012


From: "Daniel P. Berrange" <berrange at 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




More information about the libvir-list mailing list