summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/namei.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-22 01:24:22 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-22 01:24:22 +0200
commit99313414dda451a8c00b139afc77a803e647f309 (patch)
tree8f23042ffbbd231154c6eceb469fcb9c941c4b7f /fs/overlayfs/namei.c
parentMerge branch 'for-linus' of git://git.kernel.dk/linux-block (diff)
parentovl: check for bad and whiteout index on lookup (diff)
downloadlinux-99313414dda451a8c00b139afc77a803e647f309.tar.xz
linux-99313414dda451a8c00b139afc77a803e647f309.zip
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs fixes from Miklos Szeredi: "This fixes a crash with SELinux and several other old and new bugs" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: check for bad and whiteout index on lookup ovl: do not cleanup directory and whiteout index entries ovl: fix xattr get and set with selinux ovl: remove unneeded check for IS_ERR() ovl: fix origin verification of index dir ovl: mark parent impure on ovl_link() ovl: fix random return value on mount
Diffstat (limited to 'fs/overlayfs/namei.c')
-rw-r--r--fs/overlayfs/namei.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 9bc0e580a5b3..8aef2b304b2d 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -397,8 +397,19 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack,
if (!d_inode(index))
return 0;
- err = -EISDIR;
- if (d_is_dir(index))
+ /*
+ * Directory index entries are going to be used for looking up
+ * redirected upper dirs by lower dir fh when decoding an overlay
+ * file handle of a merge dir. Whiteout index entries are going to be
+ * used as an indication that an exported overlay file handle should
+ * be treated as stale (i.e. after unlink of the overlay inode).
+ * We don't know the verification rules for directory and whiteout
+ * index entries, because they have not been implemented yet, so return
+ * EROFS if those entries are found to avoid corrupting an index that
+ * was created by a newer kernel.
+ */
+ err = -EROFS;
+ if (d_is_dir(index) || ovl_is_whiteout(index))
goto fail;
err = -EINVAL;
@@ -436,8 +447,8 @@ out:
return err;
fail:
- pr_warn_ratelimited("overlayfs: failed to verify index (%pd2, err=%i)\n",
- index, err);
+ pr_warn_ratelimited("overlayfs: failed to verify index (%pd2, ftype=%x, err=%i)\n",
+ index, d_inode(index)->i_mode & S_IFMT, err);
goto out;
}
@@ -502,6 +513,7 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
goto out;
}
+ inode = d_inode(index);
if (d_is_negative(index)) {
if (upper && d_inode(origin)->i_nlink > 1) {
pr_warn_ratelimited("overlayfs: hard link with origin but no index (ino=%lu).\n",
@@ -511,11 +523,22 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
dput(index);
index = NULL;
- } else if (upper && d_inode(index) != d_inode(upper)) {
- inode = d_inode(index);
- pr_warn_ratelimited("overlayfs: wrong index found (index ino: %lu, upper ino: %lu).\n",
- d_inode(index)->i_ino,
- d_inode(upper)->i_ino);
+ } else if (upper && d_inode(upper) != inode) {
+ pr_warn_ratelimited("overlayfs: wrong index found (index=%pd2, ino=%lu, upper ino=%lu).\n",
+ index, inode->i_ino, d_inode(upper)->i_ino);
+ goto fail;
+ } else if (ovl_dentry_weird(index) || ovl_is_whiteout(index) ||
+ ((inode->i_mode ^ d_inode(origin)->i_mode) & S_IFMT)) {
+ /*
+ * Index should always be of the same file type as origin
+ * except for the case of a whiteout index. A whiteout
+ * index should only exist if all lower aliases have been
+ * unlinked, which means that finding a lower origin on lookup
+ * whose index is a whiteout should be treated as an error.
+ */
+ pr_warn_ratelimited("overlayfs: bad index found (index=%pd2, ftype=%x, origin ftype=%x).\n",
+ index, d_inode(index)->i_mode & S_IFMT,
+ d_inode(origin)->i_mode & S_IFMT);
goto fail;
}