|
|
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 |
|