Some programs want to change some values for the network interfaces
configuration in /proc/sys/net/ipv[46] folders. Giving RW access on them
allows wicked to work on openSUSE 13.2+.
In order to mount those folders RW but keep the rest of /proc/sys RO,
we add temporary mounts for these folders before bind-mounting
/proc/sys.
---
src/lxc/lxc_container.c | 97 +++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 82 insertions(+), 15 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 3b08b86..8eb2547 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -800,15 +800,20 @@ typedef struct {
int mflags;
bool skipUserNS;
bool skipUnmounted;
+ bool temporary;
} virLXCBasicMountInfo;
static const virLXCBasicMountInfo lxcBasicMounts[] = {
- { "proc", "/proc", "proc",
MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false },
- { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false
},
- { "sysfs", "/sys", "sysfs",
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false },
- { "securityfs", "/sys/kernel/security", "securityfs",
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true },
+ { "proc", "/proc", "proc",
MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
+ { "/proc/sys/net/ipv4", "TMP1", NULL, MS_BIND, false, false, true
},
+ { "/proc/sys/net/ipv6", "TMP2", NULL, MS_BIND, false, false, true
},
+ { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false,
false, false },
+ { "TMP1", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false,
false },
+ { "TMP2", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false,
false },
+ { "sysfs", "/sys", "sysfs",
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
+ { "securityfs", "/sys/kernel/security", "securityfs",
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },
#if WITH_SELINUX
- { SELINUX_MOUNT, SELINUX_MOUNT, "selinuxfs",
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true },
+ { SELINUX_MOUNT, SELINUX_MOUNT, "selinuxfs",
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },
#endif
};
@@ -885,14 +890,23 @@ static int lxcContainerSetReadOnly(void)
static int lxcContainerMountBasicFS(bool userns_enabled,
bool netns_disabled)
{
- size_t i;
+ size_t i, j;
int rc = -1;
char* mnt_src = NULL;
+ char* mnt_dst = NULL;
int mnt_mflags;
+ char **tmpkeys = NULL;
+ char **tmppaths = NULL;
+ size_t nmounts = ARRAY_CARDINALITY(lxcBasicMounts);
VIR_DEBUG("Mounting basic filesystems");
- for (i = 0; i < ARRAY_CARDINALITY(lxcBasicMounts); i++) {
+ if (VIR_ALLOC_N(tmpkeys, nmounts) < 0 ||
+ VIR_ALLOC_N(tmppaths, nmounts) < 0) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < nmounts; i++) {
bool bindOverReadonly;
virLXCBasicMountInfo const *mnt = &lxcBasicMounts[i];
@@ -906,11 +920,36 @@ static int lxcContainerMountBasicFS(bool userns_enabled,
goto cleanup;
mnt_mflags = MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY|MS_BIND;
} else {
- if (VIR_STRDUP(mnt_src, mnt->src) < 0)
+ /* Look for potential temporary folder match */
+ for (j = 0; j < i; j++) {
+ if (STREQ_NULLABLE(mnt->src, tmpkeys[j])) {
+ if (VIR_STRDUP(mnt_src, tmppaths[j]) < 0)
+ goto cleanup;
+ break;
+ }
+ }
+ if (!mnt_src && VIR_STRDUP(mnt_src, mnt->src) < 0)
goto cleanup;
mnt_mflags = mnt->mflags;
}
+ if (mnt->temporary) {
+ char tmppath[] = "/tmp/mount-XXXXXX";
+ if (mkdtemp(tmppath) == NULL) {
+ virReportSystemError(errno,
+ _("Failed to create temporary folder
%s"),
+ tmppath);
+ }
+ if (VIR_STRDUP(tmppaths[i], tmppath) < 0 ||
+ VIR_STRDUP(tmpkeys[i], mnt->dst) < 0 ||
+ VIR_STRDUP(mnt_dst, tmppath) < 0) {
+ goto cleanup;
+ }
+ } else {
+ if (VIR_STRDUP(mnt_dst, mnt->dst) < 0)
+ goto cleanup;
+ }
+
VIR_DEBUG("Processing %s -> %s",
mnt_src, mnt->dst);
@@ -940,10 +979,18 @@ static int lxcContainerMountBasicFS(bool userns_enabled,
continue;
}
- if (virFileMakePath(mnt->dst) < 0) {
+ /* Some source files or folders may not exist like /proc/sys/net/ipv6
+ * as they may depend on a kernel module being loaded. */
+ if (STRPREFIX(mnt_src, "/") && virFileExists(mnt_src)) {
+ VIR_DEBUG("Skipping: missing %s", mnt_src);
+ VIR_FREE(mnt_src);
+ continue;
+ }
+
+ if (virFileMakePath(mnt_dst) < 0) {
virReportSystemError(errno,
_("Failed to mkdir %s"),
- mnt_src);
+ mnt_dst);
goto cleanup;
}
@@ -957,32 +1004,52 @@ static int lxcContainerMountBasicFS(bool userns_enabled,
bindOverReadonly = !!(mnt_mflags & MS_RDONLY);
VIR_DEBUG("Mount %s on %s type=%s flags=%x",
- mnt_src, mnt->dst, mnt->type, mnt_mflags & ~MS_RDONLY);
- if (mount(mnt_src, mnt->dst, mnt->type, mnt_mflags & ~MS_RDONLY, NULL)
< 0) {
+ mnt_src, mnt_dst, mnt->type, mnt_mflags & ~MS_RDONLY);
+ if (mount(mnt_src, mnt_dst, mnt->type, mnt_mflags & ~MS_RDONLY, NULL) <
0) {
virReportSystemError(errno,
_("Failed to mount %s on %s type %s
flags=%x"),
- mnt_src, mnt->dst, NULLSTR(mnt->type),
+ mnt_src, mnt_dst, NULLSTR(mnt->type),
mnt_mflags & ~MS_RDONLY);
goto cleanup;
}
if (bindOverReadonly &&
- mount(mnt_src, mnt->dst, NULL,
+ mount(mnt_src, mnt_dst, NULL,
MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
virReportSystemError(errno,
_("Failed to re-mount %s on %s flags=%x"),
- mnt_src, mnt->dst,
+ mnt_src, mnt_dst,
MS_BIND|MS_REMOUNT|MS_RDONLY);
goto cleanup;
}
VIR_FREE(mnt_src);
+ VIR_FREE(mnt_dst);
}
rc = 0;
cleanup:
+ /* Cleanup temporary mounts */
+ for (i = 0; i < nmounts; i++) {
+ virLXCBasicMountInfo const *mnt = &lxcBasicMounts[i];
+ if (mnt->temporary) {
+ if (umount(tmppaths[i]) < 0) {
+ virReportSystemError(errno,
+ _("Failed to un-mount temporary %s"),
+ tmppaths[i]);
+ }
+ if (virFileDeleteTree(tmppaths[i]) < 0)
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to remove temporary folder %s"),
+ tmppaths[i]);
+ }
+ }
+
+ virStringFreeList(tmpkeys);
+ virStringFreeList(tmppaths);
VIR_FREE(mnt_src);
+ VIR_FREE(mnt_dst);
VIR_DEBUG("rc=%d", rc);
return rc;
}
--
2.1.2