diff --git a/debian/changelog b/debian/changelog index 67bb99989..e108ba183 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 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 000000000..84a92514f --- /dev/null +++ b/debian/patches/bugfix/all/-ovl-don-t-traverse-automount-points.patch @@ -0,0 +1,50 @@ +From: Miklos Szeredi +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 +--- + 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 000000000..903118e94 --- /dev/null +++ b/debian/patches/bugfix/all/fix-a-braino-in-ovl_d_select_inode.patch @@ -0,0 +1,28 @@ +From: Al Viro +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 +Tested-By: Andrey Jr. Melnikov +Signed-off-by: Al Viro +--- + 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 000000000..66976e292 --- /dev/null +++ b/debian/patches/bugfix/all/ovl-allow-distributed-fs-as-lower-layer.patch @@ -0,0 +1,227 @@ +From: Miklos Szeredi +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 +--- + 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 756d4fa37..98e0e4a72 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