Commit c9f27f9f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs

Pull overlayfs fixes from Miklos Szeredi:
 "Fix several issues, most of them introduced in the last release"

* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: do not cleanup unsupported index entries
  ovl: handle ENOENT on index lookup
  ovl: fix EIO from lookup of non-indexed upper
  ovl: Return -ENOMEM if an allocation fails ovl_lookup()
  ovl: add NULL check in ovl_alloc_inode
parents a9af9835 fa0096e3
...@@ -598,18 +598,30 @@ static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry, ...@@ -598,18 +598,30 @@ static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry,
return true; return true;
} }
struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry) struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry,
struct dentry *index)
{ {
struct dentry *lowerdentry = ovl_dentry_lower(dentry); struct dentry *lowerdentry = ovl_dentry_lower(dentry);
struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL; struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
struct inode *inode; struct inode *inode;
/* Already indexed or could be indexed on copy up? */
bool indexed = (index || (ovl_indexdir(dentry->d_sb) && !upperdentry));
if (WARN_ON(upperdentry && indexed && !lowerdentry))
return ERR_PTR(-EIO);
if (!realinode) if (!realinode)
realinode = d_inode(lowerdentry); realinode = d_inode(lowerdentry);
if (!S_ISDIR(realinode->i_mode) && /*
(upperdentry || (lowerdentry && ovl_indexdir(dentry->d_sb)))) { * Copy up origin (lower) may exist for non-indexed upper, but we must
struct inode *key = d_inode(lowerdentry ?: upperdentry); * not use lower as hash key in that case.
* Hash inodes that are or could be indexed by origin inode and
* non-indexed upper inodes that could be hard linked by upper inode.
*/
if (!S_ISDIR(realinode->i_mode) && (upperdentry || indexed)) {
struct inode *key = d_inode(indexed ? lowerdentry :
upperdentry);
unsigned int nlink; unsigned int nlink;
inode = iget5_locked(dentry->d_sb, (unsigned long) key, inode = iget5_locked(dentry->d_sb, (unsigned long) key,
......
...@@ -405,14 +405,13 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack, ...@@ -405,14 +405,13 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack,
* be treated as stale (i.e. after unlink of the overlay inode). * be treated as stale (i.e. after unlink of the overlay inode).
* We don't know the verification rules for directory and whiteout * We don't know the verification rules for directory and whiteout
* index entries, because they have not been implemented yet, so return * index entries, because they have not been implemented yet, so return
* EROFS if those entries are found to avoid corrupting an index that * EINVAL if those entries are found to abort the mount to avoid
* was created by a newer kernel. * corrupting an index that was created by a newer kernel.
*/ */
err = -EROFS; err = -EINVAL;
if (d_is_dir(index) || ovl_is_whiteout(index)) if (d_is_dir(index) || ovl_is_whiteout(index))
goto fail; goto fail;
err = -EINVAL;
if (index->d_name.len < sizeof(struct ovl_fh)*2) if (index->d_name.len < sizeof(struct ovl_fh)*2)
goto fail; goto fail;
...@@ -507,6 +506,10 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry, ...@@ -507,6 +506,10 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len); index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);
if (IS_ERR(index)) { if (IS_ERR(index)) {
err = PTR_ERR(index); err = PTR_ERR(index);
if (err == -ENOENT) {
index = NULL;
goto out;
}
pr_warn_ratelimited("overlayfs: failed inode index lookup (ino=%lu, key=%*s, err=%i);\n" pr_warn_ratelimited("overlayfs: failed inode index lookup (ino=%lu, key=%*s, err=%i);\n"
"overlayfs: mount with '-o index=off' to disable inodes index.\n", "overlayfs: mount with '-o index=off' to disable inodes index.\n",
d_inode(origin)->i_ino, name.len, name.name, d_inode(origin)->i_ino, name.len, name.name,
...@@ -516,18 +519,9 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry, ...@@ -516,18 +519,9 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
inode = d_inode(index); inode = d_inode(index);
if (d_is_negative(index)) { if (d_is_negative(index)) {
if (upper && d_inode(origin)->i_nlink > 1) { goto out_dput;
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;
} else if (upper && d_inode(upper) != inode) { } else if (upper && d_inode(upper) != inode) {
pr_warn_ratelimited("overlayfs: wrong index found (index=%pd2, ino=%lu, upper ino=%lu).\n", goto out_dput;
index, inode->i_ino, d_inode(upper)->i_ino);
goto fail;
} else if (ovl_dentry_weird(index) || ovl_is_whiteout(index) || } else if (ovl_dentry_weird(index) || ovl_is_whiteout(index) ||
((inode->i_mode ^ d_inode(origin)->i_mode) & S_IFMT)) { ((inode->i_mode ^ d_inode(origin)->i_mode) & S_IFMT)) {
/* /*
...@@ -547,6 +541,11 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry, ...@@ -547,6 +541,11 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
kfree(name.name); kfree(name.name);
return index; return index;
out_dput:
dput(index);
index = NULL;
goto out;
fail: fail:
dput(index); dput(index);
index = ERR_PTR(-EIO); index = ERR_PTR(-EIO);
...@@ -635,6 +634,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -635,6 +634,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
} }
if (d.redirect) { if (d.redirect) {
err = -ENOMEM;
upperredirect = kstrdup(d.redirect, GFP_KERNEL); upperredirect = kstrdup(d.redirect, GFP_KERNEL);
if (!upperredirect) if (!upperredirect)
goto out_put_upper; goto out_put_upper;
...@@ -709,7 +709,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -709,7 +709,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
upperdentry = dget(index); upperdentry = dget(index);
if (upperdentry || ctr) { if (upperdentry || ctr) {
inode = ovl_get_inode(dentry, upperdentry); inode = ovl_get_inode(dentry, upperdentry, index);
err = PTR_ERR(inode); err = PTR_ERR(inode);
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_free_oe; goto out_free_oe;
......
...@@ -286,7 +286,8 @@ int ovl_update_time(struct inode *inode, struct timespec *ts, int flags); ...@@ -286,7 +286,8 @@ int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
bool ovl_is_private_xattr(const char *name); bool ovl_is_private_xattr(const char *name);
struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev); struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev);
struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry); struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry,
struct dentry *index);
static inline void ovl_copyattr(struct inode *from, struct inode *to) static inline void ovl_copyattr(struct inode *from, struct inode *to)
{ {
to->i_uid = from->i_uid; to->i_uid = from->i_uid;
......
...@@ -1021,13 +1021,12 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt, ...@@ -1021,13 +1021,12 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
break; break;
} }
err = ovl_verify_index(index, lowerstack, numlower); err = ovl_verify_index(index, lowerstack, numlower);
if (err) { /* Cleanup stale and orphan index entries */
if (err == -EROFS) if (err && (err == -ESTALE || err == -ENOENT))
break;
err = ovl_cleanup(dir, index); err = ovl_cleanup(dir, index);
if (err) if (err)
break; break;
}
dput(index); dput(index);
index = NULL; index = NULL;
} }
......
...@@ -174,6 +174,9 @@ static struct inode *ovl_alloc_inode(struct super_block *sb) ...@@ -174,6 +174,9 @@ static struct inode *ovl_alloc_inode(struct super_block *sb)
{ {
struct ovl_inode *oi = kmem_cache_alloc(ovl_inode_cachep, GFP_KERNEL); struct ovl_inode *oi = kmem_cache_alloc(ovl_inode_cachep, GFP_KERNEL);
if (!oi)
return NULL;
oi->cache = NULL; oi->cache = NULL;
oi->redirect = NULL; oi->redirect = NULL;
oi->version = 0; oi->version = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment