[linux] 01/01: ovl: Add support for NFS as lower filesystem (Closes: #786925)

debian-kernel at lists.debian.org debian-kernel at lists.debian.org
Wed Aug 12 10:21:09 UTC 2015


This is an automated email from the git hooks/post-receive script.

benh pushed a commit to branch sid
in repository linux.

commit 517cfd5213de4484e9dda82c608b918578bfd5e0
Author: Ben Hutchings <ben at decadent.org.uk>
Date:   Wed Aug 12 12:20:56 2015 +0200

    ovl: Add support for NFS as lower filesystem (Closes: #786925)
---
 debian/changelog                                   |   1 +
 .../all/-ovl-don-t-traverse-automount-points.patch |  50 +++++
 .../all/fix-a-braino-in-ovl_d_select_inode.patch   |  28 +++
 .../ovl-allow-distributed-fs-as-lower-layer.patch  | 227 +++++++++++++++++++++
 debian/patches/series                              |   3 +
 5 files changed, 309 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 67bb999..e108ba1 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -345,6 +345,7 @@ linux (4.1.5-1) UNRELEASED; urgency=medium
     - README.Debian, README.source: Update references to svn
   * Bump ABI to 2
   * virtio-net: drop NETIF_F_FRAGLIST (CVE-2015-5156)
+  * ovl: Add support for NFS as lower filesystem (Closes: #786925)
 
  -- Ian Campbell <ijc at debian.org>  Tue, 04 Aug 2015 19:31:45 +0100
 
diff --git a/debian/patches/bugfix/all/-ovl-don-t-traverse-automount-points.patch b/debian/patches/bugfix/all/-ovl-don-t-traverse-automount-points.patch
new file mode 100644
index 0000000..84a9251
--- /dev/null
+++ b/debian/patches/bugfix/all/-ovl-don-t-traverse-automount-points.patch
@@ -0,0 +1,50 @@
+From: Miklos Szeredi <mszeredi at suse.cz>
+Date: Mon, 22 Jun 2015 13:53:48 +0200
+Subject: ovl: don't traverse automount points
+Origin: https://git.kernel.org/linus/a6f15d9a756571babbb2b2cd4fdd1b64a5de232b
+Bug-Debian: https://bugs.debian.org/786925
+
+NFS and other distributed filesystems may place automount points in the
+tree.  Previoulsy overlayfs refused to mount such filesystems types (based
+on the existence of the .d_automount callback), even if the actual export
+didn't have any automount points.
+
+It cannot be determined in advance whether the filesystem has automount
+points or not.  The solution is to allow fs with .d_automount but refuse to
+traverse any automount points encountered.
+
+Signed-off-by: Miklos Szeredi <mszeredi at suse.cz>
+---
+ fs/overlayfs/super.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+index bf8537c..de9d2ee 100644
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -303,6 +303,10 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir,
+ 	} else if (!dentry->d_inode) {
+ 		dput(dentry);
+ 		dentry = NULL;
++	} else if (dentry->d_flags & DCACHE_MANAGED_DENTRY) {
++		dput(dentry);
++		/* Don't support traversing automounts */
++		dentry = ERR_PTR(-EREMOTE);
+ 	}
+ 	return dentry;
+ }
+@@ -700,12 +704,12 @@ static bool ovl_is_allowed_fs_type(struct dentry *root)
+ 
+ 	/*
+ 	 * We don't support:
+-	 *  - automount filesystems
++	 *  - autofs
+ 	 *  - filesystems with revalidate (FIXME for lower layer)
+ 	 *  - filesystems with case insensitive names
+ 	 */
+ 	if (dop &&
+-	    (dop->d_manage || dop->d_automount ||
++	    (dop->d_manage ||
+ 	     dop->d_revalidate || dop->d_weak_revalidate ||
+ 	     dop->d_compare || dop->d_hash)) {
+ 		return false;
diff --git a/debian/patches/bugfix/all/fix-a-braino-in-ovl_d_select_inode.patch b/debian/patches/bugfix/all/fix-a-braino-in-ovl_d_select_inode.patch
new file mode 100644
index 0000000..903118e
--- /dev/null
+++ b/debian/patches/bugfix/all/fix-a-braino-in-ovl_d_select_inode.patch
@@ -0,0 +1,28 @@
+From: Al Viro <viro at zeniv.linux.org.uk>
+Date: Sun, 12 Jul 2015 10:39:45 -0400
+Subject: fix a braino in ovl_d_select_inode()
+Origin: https://git.kernel.org/linus/9391dd00d13c853ab4f2a85435288ae2202e0e43
+Bug-Debian: https://bugs.debian.org/786925
+
+when opening a directory we want the overlayfs inode, not one from
+the topmost layer.
+
+Reported-By: Andrey Jr. Melnikov <temnota.am at gmail.com>
+Tested-By: Andrey Jr. Melnikov <temnota.am at gmail.com>
+Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
+---
+ fs/overlayfs/inode.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/overlayfs/inode.c
++++ b/fs/overlayfs/inode.c
+@@ -344,6 +344,9 @@ static int ovl_dentry_open(struct dentry
+ 	enum ovl_path_type type;
+ 	bool want_write = false;
+ 
++	if (d_is_dir(dentry))
++		return d_backing_inode(dentry);
++
+ 	type = ovl_path_real(dentry, &realpath);
+ 	if (ovl_open_need_copy_up(file->f_flags, type, realpath.dentry)) {
+ 		want_write = true;
diff --git a/debian/patches/bugfix/all/ovl-allow-distributed-fs-as-lower-layer.patch b/debian/patches/bugfix/all/ovl-allow-distributed-fs-as-lower-layer.patch
new file mode 100644
index 0000000..66976e2
--- /dev/null
+++ b/debian/patches/bugfix/all/ovl-allow-distributed-fs-as-lower-layer.patch
@@ -0,0 +1,227 @@
+From: Miklos Szeredi <mszeredi at suse.cz>
+Date: Mon, 22 Jun 2015 13:53:48 +0200
+Subject: ovl: allow distributed fs as lower layer
+Origin: https://git.kernel.org/linus/7c03b5d45b8eebf0111125053d8fe887cc262ba6
+Bug-Debian: https://bugs.debian.org/786925
+
+Allow filesystems with .d_revalidate as lower layer(s), but not as upper
+layer.
+
+For local filesystems the rule was that modifications on the layers
+directly while being part of the overlay results in undefined behavior.
+
+This can easily be extended to distributed filesystems: we assume the tree
+used as lower layer is static, which means ->d_revalidate() should always
+return "1".  If that is not the case, return -ESTALE, don't try to work
+around the modification.
+
+Signed-off-by: Miklos Szeredi <mszeredi at suse.cz>
+---
+ fs/overlayfs/super.c | 113 +++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 88 insertions(+), 25 deletions(-)
+
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+index de9d2ee..8a08c58 100644
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -273,10 +273,57 @@ static void ovl_dentry_release(struct dentry *dentry)
+ 	}
+ }
+ 
++static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++	unsigned int i;
++	int ret = 1;
++
++	for (i = 0; i < oe->numlower; i++) {
++		struct dentry *d = oe->lowerstack[i].dentry;
++
++		if (d->d_flags & DCACHE_OP_REVALIDATE) {
++			ret = d->d_op->d_revalidate(d, flags);
++			if (ret < 0)
++				return ret;
++			if (!ret) {
++				if (!(flags & LOOKUP_RCU))
++					d_invalidate(d);
++				return -ESTALE;
++			}
++		}
++	}
++	return 1;
++}
++
++static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++	unsigned int i;
++	int ret = 1;
++
++	for (i = 0; i < oe->numlower; i++) {
++		struct dentry *d = oe->lowerstack[i].dentry;
++
++		if (d->d_flags & DCACHE_OP_WEAK_REVALIDATE) {
++			ret = d->d_op->d_weak_revalidate(d, flags);
++			if (ret <= 0)
++				break;
++		}
++	}
++	return ret;
++}
++
+ static const struct dentry_operations ovl_dentry_operations = {
+ 	.d_release = ovl_dentry_release,
+ };
+ 
++static const struct dentry_operations ovl_reval_dentry_operations = {
++	.d_release = ovl_dentry_release,
++	.d_revalidate = ovl_dentry_revalidate,
++	.d_weak_revalidate = ovl_dentry_weak_revalidate,
++};
++
+ static struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
+ {
+ 	size_t size = offsetof(struct ovl_entry, lowerstack[numlower]);
+@@ -288,6 +335,20 @@ static struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
+ 	return oe;
+ }
+ 
++static bool ovl_dentry_remote(struct dentry *dentry)
++{
++	return dentry->d_flags &
++		(DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
++}
++
++static bool ovl_dentry_weird(struct dentry *dentry)
++{
++	return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT |
++				  DCACHE_MANAGE_TRANSIT |
++				  DCACHE_OP_HASH |
++				  DCACHE_OP_COMPARE);
++}
++
+ static inline struct dentry *ovl_lookup_real(struct dentry *dir,
+ 					     struct qstr *name)
+ {
+@@ -303,9 +364,9 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir,
+ 	} else if (!dentry->d_inode) {
+ 		dput(dentry);
+ 		dentry = NULL;
+-	} else if (dentry->d_flags & DCACHE_MANAGED_DENTRY) {
++	} else if (ovl_dentry_weird(dentry)) {
+ 		dput(dentry);
+-		/* Don't support traversing automounts */
++		/* Don't support traversing automounts and other weirdness */
+ 		dentry = ERR_PTR(-EREMOTE);
+ 	}
+ 	return dentry;
+@@ -354,6 +415,11 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
+ 			goto out;
+ 
+ 		if (this) {
++			if (unlikely(ovl_dentry_remote(this))) {
++				dput(this);
++				err = -EREMOTE;
++				goto out;
++			}
+ 			if (ovl_is_whiteout(this)) {
+ 				dput(this);
+ 				this = NULL;
+@@ -698,25 +764,6 @@ static void ovl_unescape(char *s)
+ 	}
+ }
+ 
+-static bool ovl_is_allowed_fs_type(struct dentry *root)
+-{
+-	const struct dentry_operations *dop = root->d_op;
+-
+-	/*
+-	 * We don't support:
+-	 *  - autofs
+-	 *  - filesystems with revalidate (FIXME for lower layer)
+-	 *  - filesystems with case insensitive names
+-	 */
+-	if (dop &&
+-	    (dop->d_manage ||
+-	     dop->d_revalidate || dop->d_weak_revalidate ||
+-	     dop->d_compare || dop->d_hash)) {
+-		return false;
+-	}
+-	return true;
+-}
+-
+ static int ovl_mount_dir_noesc(const char *name, struct path *path)
+ {
+ 	int err = -EINVAL;
+@@ -731,7 +778,7 @@ static int ovl_mount_dir_noesc(const char *name, struct path *path)
+ 		goto out;
+ 	}
+ 	err = -EINVAL;
+-	if (!ovl_is_allowed_fs_type(path->dentry)) {
++	if (ovl_dentry_weird(path->dentry)) {
+ 		pr_err("overlayfs: filesystem on '%s' not supported\n", name);
+ 		goto out_put;
+ 	}
+@@ -755,13 +802,21 @@ static int ovl_mount_dir(const char *name, struct path *path)
+ 	if (tmp) {
+ 		ovl_unescape(tmp);
+ 		err = ovl_mount_dir_noesc(tmp, path);
++
++		if (!err)
++			if (ovl_dentry_remote(path->dentry)) {
++				pr_err("overlayfs: filesystem on '%s' not supported as upperdir\n",
++				       tmp);
++				path_put(path);
++				err = -EINVAL;
++			}
+ 		kfree(tmp);
+ 	}
+ 	return err;
+ }
+ 
+ static int ovl_lower_dir(const char *name, struct path *path, long *namelen,
+-			 int *stack_depth)
++			 int *stack_depth, bool *remote)
+ {
+ 	int err;
+ 	struct kstatfs statfs;
+@@ -778,6 +833,9 @@ static int ovl_lower_dir(const char *name, struct path *path, long *namelen,
+ 	*namelen = max(*namelen, statfs.f_namelen);
+ 	*stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth);
+ 
++	if (ovl_dentry_remote(path->dentry))
++		*remote = true;
++
+ 	return 0;
+ 
+ out_put:
+@@ -831,6 +889,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
+ 	unsigned int numlower;
+ 	unsigned int stacklen = 0;
+ 	unsigned int i;
++	bool remote = false;
+ 	int err;
+ 
+ 	err = -ENOMEM;
+@@ -904,7 +963,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
+ 	lower = lowertmp;
+ 	for (numlower = 0; numlower < stacklen; numlower++) {
+ 		err = ovl_lower_dir(lower, &stack[numlower],
+-				    &ufs->lower_namelen, &sb->s_stack_depth);
++				    &ufs->lower_namelen, &sb->s_stack_depth,
++				    &remote);
+ 		if (err)
+ 			goto out_put_lowerpath;
+ 
+@@ -962,7 +1022,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
+ 	if (!ufs->upper_mnt)
+ 		sb->s_flags |= MS_RDONLY;
+ 
+-	sb->s_d_op = &ovl_dentry_operations;
++	if (remote)
++		sb->s_d_op = &ovl_reval_dentry_operations;
++	else
++		sb->s_d_op = &ovl_dentry_operations;
+ 
+ 	err = -ENOMEM;
+ 	oe = ovl_alloc_entry(numlower);
diff --git a/debian/patches/series b/debian/patches/series
index 756d4fa..98e0e4a 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -97,3 +97,6 @@ features/all/grsecurity/grsecurity-kconfig.patch
 #features/all/grsecurity/grsecurity-kbuild.patch
 features/all/grsecurity/grkernsec_perf_harden.patch
 bugfix/all/virtio-net-drop-netif_f_fraglist.patch
+bugfix/all/-ovl-don-t-traverse-automount-points.patch
+bugfix/all/ovl-allow-distributed-fs-as-lower-layer.patch
+bugfix/all/fix-a-braino-in-ovl_d_select_inode.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/kernel/linux.git



More information about the Kernel-svn-changes mailing list