[libvirt] [PATCH] Ensure root filesystem is recursively mounted readonly
Gao feng
gaofeng at cn.fujitsu.com
Tue Sep 10 01:58:13 UTC 2013
On 09/09/2013 11:30 PM, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange at redhat.com>
>
> If the guest is configured with
>
> <filesystem type='mount'>
> <source dir='/'/>
> <target dir='/'/>
> <readonly/>
> </filesystem>
>
> Then any submounts under / should also end up readonly. eg if
> the user has /home on a separate volume, they'd expect /home
> to be readonly.
>
> Users can selectively make sub-mounts read-write again by
> simply listing them as new mounts without the <readonly>
> flag set
>
> <filesystem type='mount'>
> <source dir='/home'/>
> <target dir='/home'/>
> </filesystem>
>
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
> src/lxc/lxc_container.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 73 insertions(+), 2 deletions(-)
>
> diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
> index 9c04d06..ae672c8 100644
> --- a/src/lxc/lxc_container.c
> +++ b/src/lxc/lxc_container.c
> @@ -532,7 +532,6 @@ static int lxcContainerGetSubtree(const char *prefix,
> }
>
> while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) {
> - VIR_DEBUG("Got %s", mntent.mnt_dir);
> if (!STRPREFIX(mntent.mnt_dir, prefix))
> continue;
>
> @@ -541,7 +540,6 @@ static int lxcContainerGetSubtree(const char *prefix,
> if (VIR_STRDUP(mounts[nmounts], mntent.mnt_dir) < 0)
> goto cleanup;
> nmounts++;
> - VIR_DEBUG("Grabbed %s", mntent.mnt_dir);
> }
>
> if (mounts)
> @@ -750,6 +748,61 @@ err:
> }
>
>
> +static int lxcContainerSetReadOnly(virDomainFSDefPtr root)
> +{
> + FILE *procmnt;
> + struct mntent mntent;
> + char mntbuf[1024];
> + int ret = -1;
> + char **mounts = NULL;
> + size_t nmounts = 0;
> + size_t i;
> +
> + VIR_DEBUG("root=%s", root->src);
> +
> + if (!(procmnt = setmntent("/proc/mounts", "r"))) {
> + virReportSystemError(errno, "%s",
> + _("Failed to read /proc/mounts"));
> + return -1;
> + }
> +
> + while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) {
> + if (STREQ(mntent.mnt_dir, "/") ||
> + STRPREFIX(mntent.mnt_dir, "/.oldroot"))
> + continue;
> +
> + if (VIR_REALLOC_N(mounts, nmounts+1) < 0)
> + goto cleanup;
> + if (VIR_STRDUP(mounts[nmounts], mntent.mnt_dir) < 0)
> + goto cleanup;
> + nmounts++;
> + }
> +
> + if (mounts)
> + qsort(mounts, nmounts, sizeof(mounts[0]),
> + lxcContainerChildMountSort);
> +
> + for (i = 0 ; i < nmounts ; i++) {
> + VIR_DEBUG("Bind readonly %s", mounts[i]);
> + if (mount(mounts[i], mounts[i], NULL, MS_BIND|MS_REC|MS_RDONLY|MS_REMOUNT, NULL) < 0) {
> + virReportSystemError(errno,
> + _("Failed to make mount %s readonly"),
> + mounts[i]);
> + goto cleanup;
> + }
> + }
> +
> + ret = 0;
> +cleanup:
> + for (i = 0; i < nmounts; i++)
> + VIR_FREE(mounts[i]);
> + VIR_FREE(mounts);
> + endmntent(procmnt);
> + return ret;
> +
> +}
> +
> +
> static int lxcContainerMountBasicFS(bool userns_enabled)
> {
> const struct {
> @@ -1001,6 +1054,8 @@ static int lxcContainerMountFSBind(virDomainFSDefPtr fs,
> int ret = -1;
> struct stat st;
>
> + VIR_DEBUG("src=%s dst=%s", fs->src, fs->dst);
> +
> if (virAsprintf(&src, "%s%s", srcprefix, fs->src) < 0)
> goto cleanup;
>
> @@ -1057,6 +1112,13 @@ static int lxcContainerMountFSBind(virDomainFSDefPtr fs,
> _("Failed to make directory %s readonly"),
> fs->dst);
> }
> + } else {
> + VIR_DEBUG("Binding %s readwrite", fs->dst);
> + if (mount(src, fs->dst, NULL, MS_BIND|MS_REMOUNT, NULL) < 0) {
> + virReportSystemError(errno,
> + _("Failed to make directory %s readwrite"),
> + fs->dst);
> + }
> }
>
> ret = 0;
> @@ -1330,6 +1392,8 @@ static int lxcContainerMountFSBlock(virDomainFSDefPtr fs,
> char *src = NULL;
> int ret = -1;
>
> + VIR_DEBUG("src=%s dst=%s", fs->src, fs->dst);
> +
> if (virAsprintf(&src, "%s%s", srcprefix, fs->src) < 0)
> goto cleanup;
>
> @@ -1349,6 +1413,8 @@ static int lxcContainerMountFSTmpfs(virDomainFSDefPtr fs,
> int ret = -1;
> char *data = NULL;
>
> + VIR_DEBUG("usage=%lld sec=%s", fs->usage, sec_mount_options);
> +
> if (virAsprintf(&data,
> "size=%lldk%s", fs->usage, sec_mount_options) < 0)
> goto cleanup;
> @@ -1536,6 +1602,11 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
> if (lxcContainerMountBasicFS(vmDef->idmap.nuidmap) < 0)
> goto cleanup;
>
> + /* Ensure entire root filesystem (except /.oldroot) is readonly */
> + if (root->readonly &&
> + lxcContainerSetReadOnly(root) < 0)
> + goto cleanup;
lxcContainerSetReadOnly should be called before lxcContainerMountBasicFS,
it's meaningless to make /proc/ /sys/ readonly again.
And I would like to say user in container can still use "mount -o remount,rw --bind /"
to remount root directory writable.
More information about the libvir-list
mailing list