summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/namei.c
diff options
context:
space:
mode:
authorAmir Goldstein2017-10-12 18:03:04 +0200
committerMiklos Szeredi2017-10-24 16:06:16 +0200
commit6eaf011144af10cad34c0d46f82e50d382c8e926 (patch)
tree1b4e2491fe0a90dd60bad88c1bfa14b488cf6677 /fs/overlayfs/namei.c
parentovl: Return -ENOMEM if an allocation fails ovl_lookup() (diff)
downloadkernel-qcow2-linux-6eaf011144af10cad34c0d46f82e50d382c8e926.tar.gz
kernel-qcow2-linux-6eaf011144af10cad34c0d46f82e50d382c8e926.tar.xz
kernel-qcow2-linux-6eaf011144af10cad34c0d46f82e50d382c8e926.zip
ovl: fix EIO from lookup of non-indexed upper
Commit fbaf94ee3cd5 ("ovl: don't set origin on broken lower hardlink") attempt to avoid the condition of non-indexed upper inode with lower hardlink as origin. If this condition is found, lookup returns EIO. The protection of commit mentioned above does not cover the case of lower that is not a hardlink when it is copied up (with either index=off/on) and then lower is hardlinked while overlay is offline. Changes to lower layer while overlayfs is offline should not result in unexpected behavior, so a permanent EIO error after creating a link in lower layer should not be considered as correct behavior. This fix replaces EIO error with success in cases where upper has origin but no index is found, or index is found that does not match upper inode. In those cases, lookup will not fail and the returned overlay inode will be hashed by upper inode instead of by lower origin inode. Fixes: 359f392ca53e ("ovl: lookup index entry for copy up origin") Cc: <stable@vger.kernel.org> # v4.13 Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs/namei.c')
-rw-r--r--fs/overlayfs/namei.c20
1 files changed, 8 insertions, 12 deletions
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index e08164156cfe..05e9a0ad5c08 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -516,18 +516,9 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
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",
- d_inode(origin)->i_ino);
- goto fail;
- }
-
- dput(index);
- index = NULL;
+ goto out_dput;
} 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;
+ goto out_dput;
} else if (ovl_dentry_weird(index) || ovl_is_whiteout(index) ||
((inode->i_mode ^ d_inode(origin)->i_mode) & S_IFMT)) {
/*
@@ -547,6 +538,11 @@ out:
kfree(name.name);
return index;
+out_dput:
+ dput(index);
+ index = NULL;
+ goto out;
+
fail:
dput(index);
index = ERR_PTR(-EIO);
@@ -710,7 +706,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
upperdentry = dget(index);
if (upperdentry || ctr) {
- inode = ovl_get_inode(dentry, upperdentry);
+ inode = ovl_get_inode(dentry, upperdentry, index);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_free_oe;