From c53ba61b21b09fdf2ce0b4cf97565566a56a2f32 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 17 Jan 2012 21:33:02 +0000 Subject: [PATCH] Fix startup of LXC containers with filesystems containing symlinks 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 df8e4b0eec..0dfd4c1f1c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1101,6 +1101,7 @@ virFileOpenAs; virFileOpenTty; virFileReadAll; virFileReadLimFD; +virFileResolveAllLinks; virFileResolveLink; virFileSanitizePath; virFileStripSuffix; diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 1e7803abce..4e4388b101 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 6f46d530fb..8663c4d664 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 c9c785b49b..977ab6cc64 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;