Commit 88083e98 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:
 "This contains a fix for a potential crash/corruption issue and another
  where the suid/sgid bits weren't cleared on write"

* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: verify upper dentry in ovl_remove_and_whiteout()
  ovl: Copy up underlying inode's ->i_mode to overlay inode
  ovl: handle ATTR_KILL*
parents b1386ced cfc9fde0
...@@ -505,6 +505,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) ...@@ -505,6 +505,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
struct dentry *upper; struct dentry *upper;
struct dentry *opaquedir = NULL; struct dentry *opaquedir = NULL;
int err; int err;
int flags = 0;
if (WARN_ON(!workdir)) if (WARN_ON(!workdir))
return -EROFS; return -EROFS;
...@@ -534,46 +535,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) ...@@ -534,46 +535,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
if (err) if (err)
goto out_dput; goto out_dput;
whiteout = ovl_whiteout(workdir, dentry); upper = lookup_one_len(dentry->d_name.name, upperdir,
err = PTR_ERR(whiteout); dentry->d_name.len);
if (IS_ERR(whiteout)) err = PTR_ERR(upper);
if (IS_ERR(upper))
goto out_unlock; goto out_unlock;
upper = ovl_dentry_upper(dentry); err = -ESTALE;
if (!upper) { if ((opaquedir && upper != opaquedir) ||
upper = lookup_one_len(dentry->d_name.name, upperdir, (!opaquedir && ovl_dentry_upper(dentry) &&
dentry->d_name.len); upper != ovl_dentry_upper(dentry))) {
err = PTR_ERR(upper); goto out_dput_upper;
if (IS_ERR(upper)) }
goto kill_whiteout;
err = ovl_do_rename(wdir, whiteout, udir, upper, 0);
dput(upper);
if (err)
goto kill_whiteout;
} else {
int flags = 0;
if (opaquedir) whiteout = ovl_whiteout(workdir, dentry);
upper = opaquedir; err = PTR_ERR(whiteout);
err = -ESTALE; if (IS_ERR(whiteout))
if (upper->d_parent != upperdir) goto out_dput_upper;
goto kill_whiteout;
if (is_dir) if (d_is_dir(upper))
flags |= RENAME_EXCHANGE; flags = RENAME_EXCHANGE;
err = ovl_do_rename(wdir, whiteout, udir, upper, flags); err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
if (err) if (err)
goto kill_whiteout; goto kill_whiteout;
if (flags)
ovl_cleanup(wdir, upper);
if (is_dir)
ovl_cleanup(wdir, upper);
}
ovl_dentry_version_inc(dentry->d_parent); ovl_dentry_version_inc(dentry->d_parent);
out_d_drop: out_d_drop:
d_drop(dentry); d_drop(dentry);
dput(whiteout); dput(whiteout);
out_dput_upper:
dput(upper);
out_unlock: out_unlock:
unlock_rename(workdir, upperdir); unlock_rename(workdir, upperdir);
out_dput: out_dput:
......
...@@ -80,6 +80,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -80,6 +80,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
goto out_drop_write; goto out_drop_write;
} }
if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
attr->ia_valid &= ~ATTR_MODE;
inode_lock(upperdentry->d_inode); inode_lock(upperdentry->d_inode);
err = notify_change(upperdentry, attr, NULL); err = notify_change(upperdentry, attr, NULL);
if (!err) if (!err)
...@@ -410,12 +413,11 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, ...@@ -410,12 +413,11 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
if (!inode) if (!inode)
return NULL; return NULL;
mode &= S_IFMT;
inode->i_ino = get_next_ino(); inode->i_ino = get_next_ino();
inode->i_mode = mode; inode->i_mode = mode;
inode->i_flags |= S_NOATIME | S_NOCMTIME; inode->i_flags |= S_NOATIME | S_NOCMTIME;
mode &= S_IFMT;
switch (mode) { switch (mode) {
case S_IFDIR: case S_IFDIR:
inode->i_private = oe; inode->i_private = oe;
......
...@@ -187,6 +187,7 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to) ...@@ -187,6 +187,7 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to)
{ {
to->i_uid = from->i_uid; to->i_uid = from->i_uid;
to->i_gid = from->i_gid; to->i_gid = from->i_gid;
to->i_mode = from->i_mode;
} }
/* dir.c */ /* dir.c */
......
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