]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
pin container's rootfs to prevent read-only remount
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Tue, 31 Jul 2012 14:03:30 +0000 (16:03 +0200)
committerDaniel Lezcano <daniel.lezcano@free.fr>
Tue, 31 Jul 2012 14:03:30 +0000 (16:03 +0200)
Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/start.c

index e8088bb0973b2acfb3b83ed1dc43ad041a312226..601f4bd801e883d85316727b79dedc0d957b47e2 100644 (file)
@@ -452,6 +452,51 @@ static int mount_rootfs_block(const char *rootfs, const char *target)
        return mount_unknow_fs(rootfs, target, 0);
 }
 
+/*
+ * pin_rootfs
+ * if rootfs is a directory, then open ${rootfs}.hold for writing for the
+ * duration of the container run, to prevent the container from marking the
+ * underlying fs readonly on shutdown.
+ * return -1 on error.
+ * return -2 if nothing needed to be pinned.
+ * return an open fd (>=0) if we pinned it.
+ */
+int pin_rootfs(const char *rootfs)
+{
+       char absrootfs[MAXPATHLEN];
+       char absrootfspin[MAXPATHLEN];
+       struct stat s;
+       int ret, fd;
+
+       if (!realpath(rootfs, absrootfs)) {
+               SYSERROR("failed to get real path for '%s'", rootfs);
+               return -1;
+       }
+
+       if (access(absrootfs, F_OK)) {
+               SYSERROR("'%s' is not accessible", absrootfs);
+               return -1;
+       }
+
+       if (stat(absrootfs, &s)) {
+               SYSERROR("failed to stat '%s'", absrootfs);
+               return -1;
+       }
+
+       if (!__S_ISTYPE(s.st_mode, S_IFDIR))
+               return -2;
+
+       ret = snprintf(absrootfspin, MAXPATHLEN, "%s%s", absrootfs, ".hold");
+       if (ret >= MAXPATHLEN) {
+               SYSERROR("pathname too long for rootfs hold file");
+               return -1;
+       }
+
+       fd = open(absrootfspin, O_CREAT | O_RDWR, S_IWUSR|S_IRUSR);
+       INFO("opened %s as fd %d\n", absrootfspin, fd);
+       return fd;
+}
+
 static int mount_rootfs(const char *rootfs, const char *target)
 {
        char absrootfs[MAXPATHLEN];
index 09f55cb3fba794d36fd28be9bd9e4c53b206fdd6..0d8f28ed85a5bdd2d6bd395552cbc60c3f9a193e 100644 (file)
@@ -223,6 +223,8 @@ struct lxc_conf {
  */
 extern struct lxc_conf *lxc_conf_init(void);
 
+extern int pin_rootfs(const char *rootfs);
+
 extern int lxc_create_network(struct lxc_handler *handler);
 extern void lxc_delete_network(struct lxc_list *networks);
 extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
index 920ff77c3fd354dcf68e740464cb97f9af44671f..2938537571a28c1f674a80e398f9072e7c3a6018 100644 (file)
@@ -534,6 +534,7 @@ int lxc_spawn(struct lxc_handler *handler)
        int clone_flags;
        int failed_before_rename = 0;
        const char *name = handler->name;
+       int pinfd;
 
        if (lxc_sync_init(handler))
                return -1;
@@ -563,6 +564,17 @@ int lxc_spawn(struct lxc_handler *handler)
                }
        }
 
+       /*
+        * if the rootfs is not a blockdev, prevent the container from
+        * marking it readonly.
+        */
+
+       pinfd = pin_rootfs(handler->conf->rootfs.path);
+       if (pinfd == -1) {
+               ERROR("failed to pin the container's rootfs");
+               goto out_abort;
+       }
+
        /* Create a process in a new set of namespaces */
        handler->pid = lxc_clone(do_start, handler, clone_flags);
        if (handler->pid < 0) {
@@ -605,6 +617,10 @@ int lxc_spawn(struct lxc_handler *handler)
        }
 
        lxc_sync_fini(handler);
+
+       if (pinfd >= 0)
+               close(pinfd);
+
        return 0;
 
 out_delete_net: