Commit 88083e98 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+24 −30
Original line number Diff line number Diff line
@@ -505,6 +505,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
	struct dentry *upper;
	struct dentry *opaquedir = NULL;
	int err;
	int flags = 0;

	if (WARN_ON(!workdir))
		return -EROFS;
@@ -534,46 +535,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
	if (err)
		goto out_dput;

	whiteout = ovl_whiteout(workdir, dentry);
	err = PTR_ERR(whiteout);
	if (IS_ERR(whiteout))
		goto out_unlock;

	upper = ovl_dentry_upper(dentry);
	if (!upper) {
	upper = lookup_one_len(dentry->d_name.name, upperdir,
			       dentry->d_name.len);
	err = PTR_ERR(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;
		goto out_unlock;

		if (opaquedir)
			upper = opaquedir;
	err = -ESTALE;
		if (upper->d_parent != upperdir)
			goto kill_whiteout;
	if ((opaquedir && upper != opaquedir) ||
	    (!opaquedir && ovl_dentry_upper(dentry) &&
	     upper != ovl_dentry_upper(dentry))) {
		goto out_dput_upper;
	}

		if (is_dir)
			flags |= RENAME_EXCHANGE;
	whiteout = ovl_whiteout(workdir, dentry);
	err = PTR_ERR(whiteout);
	if (IS_ERR(whiteout))
		goto out_dput_upper;

	if (d_is_dir(upper))
		flags = RENAME_EXCHANGE;

	err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
	if (err)
		goto kill_whiteout;

		if (is_dir)
	if (flags)
		ovl_cleanup(wdir, upper);
	}

	ovl_dentry_version_inc(dentry->d_parent);
out_d_drop:
	d_drop(dentry);
	dput(whiteout);
out_dput_upper:
	dput(upper);
out_unlock:
	unlock_rename(workdir, upperdir);
out_dput:
+4 −2
Original line number Diff line number Diff line
@@ -80,6 +80,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
				goto out_drop_write;
		}

		if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
			attr->ia_valid &= ~ATTR_MODE;

		inode_lock(upperdentry->d_inode);
		err = notify_change(upperdentry, attr, NULL);
		if (!err)
@@ -410,12 +413,11 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
	if (!inode)
		return NULL;

	mode &= S_IFMT;

	inode->i_ino = get_next_ino();
	inode->i_mode = mode;
	inode->i_flags |= S_NOATIME | S_NOCMTIME;

	mode &= S_IFMT;
	switch (mode) {
	case S_IFDIR:
		inode->i_private = oe;
+1 −0
Original line number Diff line number Diff line
@@ -187,6 +187,7 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to)
{
	to->i_uid = from->i_uid;
	to->i_gid = from->i_gid;
	to->i_mode = from->i_mode;
}

/* dir.c */