[libvirt] [PATCH] lxc: give RW access to /proc/sys/net/ipv[46] to containers

Cédric Bosdonnat cbosdonnat at suse.com
Wed Dec 3 08:49:51 UTC 2014


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




More information about the libvir-list mailing list