| From 4a8570112b76a63ad21cfcbe2783f98f7fd5ba1b Mon Sep 17 00:00:00 2001 |
| From: Jeff Mahoney <jeffm@suse.com> |
| Date: Fri, 31 May 2013 15:54:17 -0400 |
| Subject: reiserfs: fix problems with chowning setuid file w/ xattrs |
| |
| From: Jeff Mahoney <jeffm@suse.com> |
| |
| commit 4a8570112b76a63ad21cfcbe2783f98f7fd5ba1b upstream. |
| |
| reiserfs_chown_xattrs() takes the iattr struct passed into ->setattr |
| and uses it to iterate over all the attrs associated with a file to change |
| ownership of xattrs (and transfer quota associated with the xattr files). |
| |
| When the setuid bit is cleared during chown, ATTR_MODE and iattr->ia_mode |
| are passed to all the xattrs as well. This means that the xattr directory |
| will have S_IFREG added to its mode bits. |
| |
| This has been prevented in practice by a missing IS_PRIVATE check |
| in reiserfs_acl_chmod, which caused a double-lock to occur while holding |
| the write lock. Since the file system was completely locked up, the |
| writeout of the corrupted mode never happened. |
| |
| This patch temporarily clears everything but ATTR_UID|ATTR_GID for the |
| calls to reiserfs_setattr and adds the missing IS_PRIVATE check. |
| |
| Signed-off-by: Jeff Mahoney <jeffm@suse.com> |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Jonghwan Choi <jhbird.choi@samsung.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/reiserfs/xattr.c | 14 +++++++++++++- |
| fs/reiserfs/xattr_acl.c | 3 +++ |
| 2 files changed, 16 insertions(+), 1 deletion(-) |
| |
| --- a/fs/reiserfs/xattr.c |
| +++ b/fs/reiserfs/xattr.c |
| @@ -318,7 +318,19 @@ static int delete_one_xattr(struct dentr |
| static int chown_one_xattr(struct dentry *dentry, void *data) |
| { |
| struct iattr *attrs = data; |
| - return reiserfs_setattr(dentry, attrs); |
| + int ia_valid = attrs->ia_valid; |
| + int err; |
| + |
| + /* |
| + * We only want the ownership bits. Otherwise, we'll do |
| + * things like change a directory to a regular file if |
| + * ATTR_MODE is set. |
| + */ |
| + attrs->ia_valid &= (ATTR_UID|ATTR_GID); |
| + err = reiserfs_setattr(dentry, attrs); |
| + attrs->ia_valid = ia_valid; |
| + |
| + return err; |
| } |
| |
| /* No i_mutex, but the inode is unconnected. */ |
| --- a/fs/reiserfs/xattr_acl.c |
| +++ b/fs/reiserfs/xattr_acl.c |
| @@ -443,6 +443,9 @@ int reiserfs_acl_chmod(struct inode *ino |
| int depth; |
| int error; |
| |
| + if (IS_PRIVATE(inode)) |
| + return 0; |
| + |
| if (S_ISLNK(inode->i_mode)) |
| return -EOPNOTSUPP; |
| |