43fe83
From 44d208f8b25e5c1e4369f671fc70915c29498b76 Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <44d208f8b25e5c1e4369f671fc70915c29498b76.1380112456.git.jdenemar@redhat.com>
43fe83
From: "Daniel P. Berrange" <berrange@redhat.com>
43fe83
Date: Fri, 20 Sep 2013 13:07:50 +0100
43fe83
Subject: [PATCH] Ensure root filesystem is recursively mounted readonly
43fe83
43fe83
For
43fe83
43fe83
  https://bugzilla.redhat.com/show_bug.cgi?id=872648
43fe83
43fe83
If the guest is configured with
43fe83
43fe83
    <filesystem type='mount'>
43fe83
      <source dir='/'/>
43fe83
      <target dir='/'/>
43fe83
      <readonly/>
43fe83
    </filesystem>
43fe83
43fe83
Then any submounts under / should also end up readonly, except
43fe83
for those setup as basic mounts. eg if the user has /home on a
43fe83
separate volume, they'd expect /home to be readonly, but we
43fe83
should not touch the /sys, /proc, etc dirs we setup ourselves.
43fe83
43fe83
Users can selectively make sub-mounts read-write again by
43fe83
simply listing them as new mounts without the <readonly>
43fe83
flag set
43fe83
43fe83
    <filesystem type='mount'>
43fe83
      <source dir='/home'/>
43fe83
      <target dir='/home'/>
43fe83
    </filesystem>
43fe83
43fe83
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
43fe83
(cherry picked from commit 75235a52bc58df5ed714ff8f937220cef9ddfe26)
43fe83
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
43fe83
---
43fe83
 src/lxc/lxc_container.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++--
43fe83
 1 file changed, 86 insertions(+), 2 deletions(-)
43fe83
43fe83
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
43fe83
index d3154d8..f851fcc 100644
43fe83
--- a/src/lxc/lxc_container.c
43fe83
+++ b/src/lxc/lxc_container.c
43fe83
@@ -532,7 +532,6 @@ static int lxcContainerGetSubtree(const char *prefix,
43fe83
     }
43fe83
 
43fe83
     while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) {
43fe83
-        VIR_DEBUG("Got %s", mntent.mnt_dir);
43fe83
         if (!STRPREFIX(mntent.mnt_dir, prefix))
43fe83
             continue;
43fe83
 
43fe83
@@ -541,7 +540,6 @@ static int lxcContainerGetSubtree(const char *prefix,
43fe83
         if (VIR_STRDUP(mounts[nmounts], mntent.mnt_dir) < 0)
43fe83
             goto cleanup;
43fe83
         nmounts++;
43fe83
-        VIR_DEBUG("Grabbed %s", mntent.mnt_dir);
43fe83
     }
43fe83
 
43fe83
     if (mounts)
43fe83
@@ -779,6 +777,74 @@ static const virLXCBasicMountInfo lxcBasicMounts[] = {
43fe83
 };
43fe83
 
43fe83
 
43fe83
+static bool lxcIsBasicMountLocation(const char *path)
43fe83
+{
43fe83
+    size_t i;
43fe83
+
43fe83
+    for (i = 0; i < ARRAY_CARDINALITY(lxcBasicMounts); i++) {
43fe83
+        if (STREQ(path, lxcBasicMounts[i].dst))
43fe83
+            return true;
43fe83
+    }
43fe83
+
43fe83
+    return false;
43fe83
+}
43fe83
+
43fe83
+
43fe83
+static int lxcContainerSetReadOnly(void)
43fe83
+{
43fe83
+    FILE *procmnt;
43fe83
+    struct mntent mntent;
43fe83
+    char mntbuf[1024];
43fe83
+    int ret = -1;
43fe83
+    char **mounts = NULL;
43fe83
+    size_t nmounts = 0;
43fe83
+    size_t i;
43fe83
+
43fe83
+    if (!(procmnt = setmntent("/proc/mounts", "r"))) {
43fe83
+        virReportSystemError(errno, "%s",
43fe83
+                             _("Failed to read /proc/mounts"));
43fe83
+        return -1;
43fe83
+    }
43fe83
+
43fe83
+    while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) {
43fe83
+        if (STREQ(mntent.mnt_dir, "/") ||
43fe83
+            STREQ(mntent.mnt_dir, "/.oldroot") ||
43fe83
+            STRPREFIX(mntent.mnt_dir, "/.oldroot/") ||
43fe83
+            lxcIsBasicMountLocation(mntent.mnt_dir))
43fe83
+            continue;
43fe83
+
43fe83
+        if (VIR_REALLOC_N(mounts, nmounts + 1) < 0)
43fe83
+            goto cleanup;
43fe83
+        if (VIR_STRDUP(mounts[nmounts], mntent.mnt_dir) < 0)
43fe83
+            goto cleanup;
43fe83
+        nmounts++;
43fe83
+    }
43fe83
+
43fe83
+    if (mounts)
43fe83
+        qsort(mounts, nmounts, sizeof(mounts[0]),
43fe83
+              lxcContainerChildMountSort);
43fe83
+
43fe83
+    for (i = 0; i < nmounts; i++) {
43fe83
+        VIR_DEBUG("Bind readonly %s", mounts[i]);
43fe83
+        if (mount(mounts[i], mounts[i], NULL, MS_BIND|MS_REC|MS_RDONLY|MS_REMOUNT, NULL) < 0) {
43fe83
+            virReportSystemError(errno,
43fe83
+                                 _("Failed to make mount %s readonly"),
43fe83
+                                 mounts[i]);
43fe83
+            goto cleanup;
43fe83
+        }
43fe83
+    }
43fe83
+
43fe83
+    ret = 0;
43fe83
+cleanup:
43fe83
+    for (i = 0; i < nmounts; i++)
43fe83
+        VIR_FREE(mounts[i]);
43fe83
+    VIR_FREE(mounts);
43fe83
+    endmntent(procmnt);
43fe83
+    return ret;
43fe83
+
43fe83
+}
43fe83
+
43fe83
+
43fe83
 static int lxcContainerMountBasicFS(bool userns_enabled)
43fe83
 {
43fe83
     size_t i;
43fe83
@@ -1006,6 +1072,8 @@ static int lxcContainerMountFSBind(virDomainFSDefPtr fs,
43fe83
     int ret = -1;
43fe83
     struct stat st;
43fe83
 
43fe83
+    VIR_DEBUG("src=%s dst=%s", fs->src, fs->dst);
43fe83
+
43fe83
     if (virAsprintf(&src, "%s%s", srcprefix, fs->src) < 0)
43fe83
         goto cleanup;
43fe83
 
43fe83
@@ -1062,6 +1130,13 @@ static int lxcContainerMountFSBind(virDomainFSDefPtr fs,
43fe83
                                  _("Failed to make directory %s readonly"),
43fe83
                                  fs->dst);
43fe83
         }
43fe83
+    } else {
43fe83
+        VIR_DEBUG("Binding %s readwrite", fs->dst);
43fe83
+        if (mount(src, fs->dst, NULL, MS_BIND|MS_REMOUNT, NULL) < 0) {
43fe83
+            virReportSystemError(errno,
43fe83
+                                 _("Failed to make directory %s readwrite"),
43fe83
+                                 fs->dst);
43fe83
+        }
43fe83
     }
43fe83
 
43fe83
     ret = 0;
43fe83
@@ -1335,6 +1410,8 @@ static int lxcContainerMountFSBlock(virDomainFSDefPtr fs,
43fe83
     char *src = NULL;
43fe83
     int ret = -1;
43fe83
 
43fe83
+    VIR_DEBUG("src=%s dst=%s", fs->src, fs->dst);
43fe83
+
43fe83
     if (virAsprintf(&src, "%s%s", srcprefix, fs->src) < 0)
43fe83
         goto cleanup;
43fe83
 
43fe83
@@ -1354,6 +1431,8 @@ static int lxcContainerMountFSTmpfs(virDomainFSDefPtr fs,
43fe83
     int ret = -1;
43fe83
     char *data = NULL;
43fe83
 
43fe83
+    VIR_DEBUG("usage=%lld sec=%s", fs->usage, sec_mount_options);
43fe83
+
43fe83
     if (virAsprintf(&data,
43fe83
                     "size=%lldk%s", fs->usage, sec_mount_options) < 0)
43fe83
         goto cleanup;
43fe83
@@ -1541,6 +1620,11 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
43fe83
     if (lxcContainerMountBasicFS(vmDef->idmap.nuidmap) < 0)
43fe83
         goto cleanup;
43fe83
 
43fe83
+    /* Ensure entire root filesystem (except /.oldroot) is readonly */
43fe83
+    if (root->readonly &&
43fe83
+        lxcContainerSetReadOnly() < 0)
43fe83
+        goto cleanup;
43fe83
+
43fe83
     /* Mounts /proc/meminfo etc sysinfo */
43fe83
     if (lxcContainerMountProcFuse(vmDef, stateDir) < 0)
43fe83
         goto cleanup;
43fe83
-- 
43fe83
1.8.3.2
43fe83