[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