Commit 1bdd629e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ovl-update-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs

Pull overlayfs updates from Miklos Szeredi:

 - Fix a regression introduced in the last cycle

 - Fix a use-after-free in the AIO path

 - Fix a bogus warning reported by syzbot

* tag 'ovl-update-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: fix filattr copy-up failure
  ovl: fix warning in ovl_create_real()
  ovl: fix use after free in struct ovl_aio_req
parents cdd39b05 5b0a414d
...@@ -140,12 +140,14 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old, ...@@ -140,12 +140,14 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
int err; int err;
err = ovl_real_fileattr_get(old, &oldfa); err = ovl_real_fileattr_get(old, &oldfa);
if (err) if (err) {
return err; /* Ntfs-3g returns -EINVAL for "no fileattr support" */
if (err == -ENOTTY || err == -EINVAL)
err = ovl_real_fileattr_get(new, &newfa); return 0;
if (err) pr_warn("failed to retrieve lower fileattr (%pd2, err=%i)\n",
old, err);
return err; return err;
}
/* /*
* We cannot set immutable and append-only flags on upper inode, * We cannot set immutable and append-only flags on upper inode,
...@@ -159,6 +161,17 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old, ...@@ -159,6 +161,17 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
return err; return err;
} }
/* Don't bother copying flags if none are set */
if (!(oldfa.flags & OVL_COPY_FS_FLAGS_MASK))
return 0;
err = ovl_real_fileattr_get(new, &newfa);
if (err) {
pr_warn("failed to retrieve upper fileattr (%pd2, err=%i)\n",
new, err);
return err;
}
BUILD_BUG_ON(OVL_COPY_FS_FLAGS_MASK & ~FS_COMMON_FL); BUILD_BUG_ON(OVL_COPY_FS_FLAGS_MASK & ~FS_COMMON_FL);
newfa.flags &= ~OVL_COPY_FS_FLAGS_MASK; newfa.flags &= ~OVL_COPY_FS_FLAGS_MASK;
newfa.flags |= (oldfa.flags & OVL_COPY_FS_FLAGS_MASK); newfa.flags |= (oldfa.flags & OVL_COPY_FS_FLAGS_MASK);
......
...@@ -137,8 +137,7 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir, ...@@ -137,8 +137,7 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir,
goto out; goto out;
} }
static int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode)
umode_t mode)
{ {
int err; int err;
struct dentry *d, *dentry = *newdentry; struct dentry *d, *dentry = *newdentry;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
struct ovl_aio_req { struct ovl_aio_req {
struct kiocb iocb; struct kiocb iocb;
refcount_t ref;
struct kiocb *orig_iocb; struct kiocb *orig_iocb;
struct fd fd; struct fd fd;
}; };
...@@ -252,6 +253,14 @@ static rwf_t ovl_iocb_to_rwf(int ifl) ...@@ -252,6 +253,14 @@ static rwf_t ovl_iocb_to_rwf(int ifl)
return flags; return flags;
} }
static inline void ovl_aio_put(struct ovl_aio_req *aio_req)
{
if (refcount_dec_and_test(&aio_req->ref)) {
fdput(aio_req->fd);
kmem_cache_free(ovl_aio_request_cachep, aio_req);
}
}
static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req) static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
{ {
struct kiocb *iocb = &aio_req->iocb; struct kiocb *iocb = &aio_req->iocb;
...@@ -268,8 +277,7 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req) ...@@ -268,8 +277,7 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
} }
orig_iocb->ki_pos = iocb->ki_pos; orig_iocb->ki_pos = iocb->ki_pos;
fdput(aio_req->fd); ovl_aio_put(aio_req);
kmem_cache_free(ovl_aio_request_cachep, aio_req);
} }
static void ovl_aio_rw_complete(struct kiocb *iocb, long res) static void ovl_aio_rw_complete(struct kiocb *iocb, long res)
...@@ -319,7 +327,9 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter) ...@@ -319,7 +327,9 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
aio_req->orig_iocb = iocb; aio_req->orig_iocb = iocb;
kiocb_clone(&aio_req->iocb, iocb, real.file); kiocb_clone(&aio_req->iocb, iocb, real.file);
aio_req->iocb.ki_complete = ovl_aio_rw_complete; aio_req->iocb.ki_complete = ovl_aio_rw_complete;
refcount_set(&aio_req->ref, 2);
ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter); ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
ovl_aio_put(aio_req);
if (ret != -EIOCBQUEUED) if (ret != -EIOCBQUEUED)
ovl_aio_cleanup_handler(aio_req); ovl_aio_cleanup_handler(aio_req);
} }
...@@ -390,7 +400,9 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter) ...@@ -390,7 +400,9 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
kiocb_clone(&aio_req->iocb, iocb, real.file); kiocb_clone(&aio_req->iocb, iocb, real.file);
aio_req->iocb.ki_flags = ifl; aio_req->iocb.ki_flags = ifl;
aio_req->iocb.ki_complete = ovl_aio_rw_complete; aio_req->iocb.ki_complete = ovl_aio_rw_complete;
refcount_set(&aio_req->ref, 2);
ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter); ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
ovl_aio_put(aio_req);
if (ret != -EIOCBQUEUED) if (ret != -EIOCBQUEUED)
ovl_aio_cleanup_handler(aio_req); ovl_aio_cleanup_handler(aio_req);
} }
......
...@@ -610,7 +610,10 @@ int ovl_real_fileattr_get(struct path *realpath, struct fileattr *fa) ...@@ -610,7 +610,10 @@ int ovl_real_fileattr_get(struct path *realpath, struct fileattr *fa)
if (err) if (err)
return err; return err;
return vfs_fileattr_get(realpath->dentry, fa); err = vfs_fileattr_get(realpath->dentry, fa);
if (err == -ENOIOCTLCMD)
err = -ENOTTY;
return err;
} }
int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa) int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa)
......
...@@ -570,6 +570,7 @@ struct ovl_cattr { ...@@ -570,6 +570,7 @@ struct ovl_cattr {
#define OVL_CATTR(m) (&(struct ovl_cattr) { .mode = (m) }) #define OVL_CATTR(m) (&(struct ovl_cattr) { .mode = (m) })
int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode);
struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry, struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
struct ovl_cattr *attr); struct ovl_cattr *attr);
int ovl_cleanup(struct inode *dir, struct dentry *dentry); int ovl_cleanup(struct inode *dir, struct dentry *dentry);
......
...@@ -787,10 +787,14 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, ...@@ -787,10 +787,14 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
goto retry; goto retry;
} }
work = ovl_create_real(dir, work, OVL_CATTR(attr.ia_mode)); err = ovl_mkdir_real(dir, &work, attr.ia_mode);
err = PTR_ERR(work); if (err)
if (IS_ERR(work)) goto out_dput;
goto out_err;
/* Weird filesystem returning with hashed negative (kernfs)? */
err = -EINVAL;
if (d_really_is_negative(work))
goto out_dput;
/* /*
* Try to remove POSIX ACL xattrs from workdir. We are good if: * Try to remove POSIX ACL xattrs from workdir. We are good if:
......
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