Patch "posix_acl: Clear SGID bit when setting file permissions" has been added to the 4.8-stable tree
Subsystems (15)
This is a note to let you know that I've just added the patch titled
posix_acl: Clear SGID bit when setting file permissions
to the 4.8-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
posix_acl-clear-sgid-bit-when-setting-file-permissions.patch
and it can be found in the queue-4.8 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
073931017b49d9458aa351605b43a7e34598caefMon Sep 17 00:00:00 2001
From: Jan Kara <[email protected]>
Date: Mon, 19 Sep 2016 17:39:09 +0200
Subject: posix_acl: Clear SGID bit when setting file permissions
From: Jan Kara <[email protected]>
commit 073931017b49d9458aa351605b43a7e34598caef upstream.
When file permissions are modified via chmod(2) and the user is not in the owning group or capable of CAP_FSETID, the setgid bit is cleared in inode_change_ok(). Setting a POSIX ACL via setxattr(2) sets the file permissions as well as the new ACL, but doesn't clear the setgid bit in a similar way; this allows to bypass the check in chmod(2). Fix that.
References: CVE-2016-7097
--- fs/9p/acl.c | 40 +++++++++++++++++----------------------- fs/btrfs/acl.c | 6 ++---- fs/ceph/acl.c | 6 ++---- fs/ext2/acl.c | 12 ++++-------- fs/ext4/acl.c | 12 ++++-------- fs/f2fs/acl.c | 6 ++---- fs/gfs2/acl.c | 12 +++--------- fs/hfsplus/posix_acl.c | 4 ++-- fs/jffs2/acl.c | 9 ++++----- fs/jfs/acl.c | 6 ++---- fs/ocfs2/acl.c | 10 ++++------ fs/orangefs/acl.c | 15 +++++---------- fs/posix_acl.c | 31 +++++++++++++++++++++++++++++++ fs/reiserfs/xattr_acl.c | 8 ++------ fs/xfs/xfs_acl.c | 13 ++++--------- include/linux/posix_acl.h | 1 + 16 files changed, 89 insertions(+), 102 deletions(-)
fs/9p/acl.c +17 -23
@@ -276,32 +276,26 @@ static int v9fs_xattr_set_acl(const struswitch (handler->flags) {case ACL_TYPE_ACCESS :if (acl) { -umode_t mode = inode->i_mode; - retval =posix_acl_equiv_mode (acl, &mode); -if (retval <0 ) +struct iattr iattr; + + retval =posix_acl_update_mode (inode, &iattr.ia_mode, &acl); +if (retval) goto err_out; -else { -struct iattr iattr; -if (retval ==0 ) { -/* -* ACL can be represented -* by the mode bits. So don't -* update ACL. -*/ - acl =NULL ; - value =NULL ; - size =0 ; - } -/* Updte the mode bits */ - iattr.ia_mode = ((mode &S_IALLUGO ) | - (inode->i_mode & ~S_IALLUGO )); - iattr.ia_valid =ATTR_MODE ; -/* FIXME should we update ctime ? -* What is the following setxattr update the -* mode ? +if (!acl) { +/* +* ACL can be represented +* by the mode bits. So don't +* update ACL. */ -v9fs_vfs_setattr_dotl (dentry, &iattr); + value =NULL ; + size =0 ; } + iattr.ia_valid =ATTR_MODE ; +/* FIXME should we update ctime ? +* What is the following setxattr update the +* mode ? +*/ +v9fs_vfs_setattr_dotl (dentry, &iattr); }break ;case ACL_TYPE_DEFAULT :
fs/btrfs/acl.c +2 -4
@@ -79,11 +79,9 @@ static int __btrfs_set_acl(struct btrfs_case ACL_TYPE_ACCESS : name =XATTR_NAME_POSIX_ACL_ACCESS ;if (acl) { - ret =posix_acl_equiv_mode (acl, &inode->i_mode); -if (ret <0 ) + ret =posix_acl_update_mode (inode, &inode->i_mode, &acl); +if (ret)return ret; -if (ret ==0 ) - acl =NULL ; } ret =0 ;break ;
fs/ceph/acl.c +2 -4
@@ -95,11 +95,9 @@ int ceph_set_acl(struct inode *inode, stcase ACL_TYPE_ACCESS : name =XATTR_NAME_POSIX_ACL_ACCESS ;if (acl) { - ret =posix_acl_equiv_mode (acl, &new_mode); -if (ret <0 ) + ret =posix_acl_update_mode (inode, &new_mode, &acl); +if (ret) goto out; -if (ret ==0 ) - acl =NULL ; }break ;case ACL_TYPE_DEFAULT :
fs/ext2/acl.c +4 -8
@@ -190,15 +190,11 @@ ext2_set_acl(struct inode *inode, structcase ACL_TYPE_ACCESS : name_index =EXT2_XATTR_INDEX_POSIX_ACL_ACCESS ;if (acl) { - error =posix_acl_equiv_mode (acl, &inode->i_mode); -if (error <0 ) + error =posix_acl_update_mode (inode, &inode->i_mode, &acl); +if (error)return error; -else { - inode->i_ctime =CURRENT_TIME_SEC ; -mark_inode_dirty (inode); -if (error ==0 ) - acl =NULL ; - } + inode->i_ctime =CURRENT_TIME_SEC ; +mark_inode_dirty (inode); }break ;
fs/ext4/acl.c +4 -8
@@ -193,15 +193,11 @@ __ext4_set_acl(handle_t *handle, structcase ACL_TYPE_ACCESS : name_index =EXT4_XATTR_INDEX_POSIX_ACL_ACCESS ;if (acl) { - error =posix_acl_equiv_mode (acl, &inode->i_mode); -if (error <0 ) + error =posix_acl_update_mode (inode, &inode->i_mode, &acl); +if (error)return error; -else { - inode->i_ctime =ext4_current_time (inode); -ext4_mark_inode_dirty (handle, inode); -if (error ==0 ) - acl =NULL ; - } + inode->i_ctime =ext4_current_time (inode); +ext4_mark_inode_dirty (handle, inode); }break ;
fs/f2fs/acl.c +2 -4
@@ -210,12 +210,10 @@ static int __f2fs_set_acl(struct inode *case ACL_TYPE_ACCESS : name_index =F2FS_XATTR_INDEX_POSIX_ACL_ACCESS ;if (acl) { - error =posix_acl_equiv_mode (acl, &inode->i_mode); -if (error <0 ) + error =posix_acl_update_mode (inode, &inode->i_mode, &acl); +if (error)return error;set_acl_inode (inode, inode->i_mode); -if (error ==0 ) - acl =NULL ; }break ;
fs/gfs2/acl.c +3 -9
@@ -92,17 +92,11 @@ int __gfs2_set_acl(struct inode *inode,if (type ==ACL_TYPE_ACCESS ) {umode_t mode = inode->i_mode; - error =posix_acl_equiv_mode (acl, &mode); -if (error <0 ) + error =posix_acl_update_mode (inode, &inode->i_mode, &acl); +if (error)return error; - -if (error ==0 ) - acl =NULL ; - -if (mode != inode->i_mode) { - inode->i_mode = mode; +if (mode != inode->i_mode)mark_inode_dirty (inode); - } }if (acl) {
fs/hfsplus/posix_acl.c +2 -2
@@ -65,8 +65,8 @@ int hfsplus_set_posix_acl(struct inode *case ACL_TYPE_ACCESS : xattr_name =XATTR_NAME_POSIX_ACL_ACCESS ;if (acl) { - err =posix_acl_equiv_mode (acl, &inode->i_mode); -if (err <0 ) + err =posix_acl_update_mode (inode, &inode->i_mode, &acl); +if (err)return err; } err =0 ;
fs/jffs2/acl.c +4 -5
@@ -233,9 +233,10 @@ int jffs2_set_acl(struct inode *inode, scase ACL_TYPE_ACCESS : xprefix =JFFS2_XPREFIX_ACL_ACCESS ;if (acl) { -umode_t mode = inode->i_mode; - rc =posix_acl_equiv_mode (acl, &mode); -if (rc <0 ) +umode_t mode; + + rc =posix_acl_update_mode (inode, &mode, &acl); +if (rc)return rc;if (inode->i_mode != mode) {struct iattr attr;
@@ -247,8 +248,6 @@ int jffs2_set_acl(struct inode *inode, sif (rc <0 )return rc; } -if (rc ==0 ) - acl =NULL ; }break ;case ACL_TYPE_DEFAULT :
fs/jfs/acl.c +2 -4
@@ -78,13 +78,11 @@ static int __jfs_set_acl(tid_t tid, strucase ACL_TYPE_ACCESS : ea_name =XATTR_NAME_POSIX_ACL_ACCESS ;if (acl) { - rc =posix_acl_equiv_mode (acl, &inode->i_mode); -if (rc <0 ) + rc =posix_acl_update_mode (inode, &inode->i_mode, &acl); +if (rc)return rc; inode->i_ctime =CURRENT_TIME ;mark_inode_dirty (inode); -if (rc ==0 ) - acl =NULL ; }break ;case ACL_TYPE_DEFAULT :
fs/ocfs2/acl.c +4 -6
@@ -241,13 +241,11 @@ int ocfs2_set_acl(handle_t *handle,case ACL_TYPE_ACCESS : name_index =OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS ;if (acl) { -umode_t mode = inode->i_mode; - ret =posix_acl_equiv_mode (acl, &mode); -if (ret <0 ) -return ret; +umode_t mode; -if (ret ==0 ) - acl =NULL ; + ret =posix_acl_update_mode (inode, &mode, &acl); +if (ret) +return ret; ret =ocfs2_acl_set_mode (inode, di_bh, handle, mode);
fs/orangefs/acl.c +5 -10
@@ -73,14 +73,11 @@ int orangefs_set_acl(struct inode *inodecase ACL_TYPE_ACCESS : name =XATTR_NAME_POSIX_ACL_ACCESS ;if (acl) { -umode_t mode = inode->i_mode; -/* -* can we represent this with the traditional file -* mode permission bits? -*/ - error =posix_acl_equiv_mode (acl, &mode); -if (error <0 ) { -gossip_err ("%s: posix_acl_equiv_mode err: %d\n" , +umode_t mode; + + error =posix_acl_update_mode (inode, &mode, &acl); +if (error) { +gossip_err ("%s: posix_acl_update_mode err: %d\n" , __func__, error);return error;
@@ -90,8 +87,6 @@ int orangefs_set_acl(struct inode *inodeSetModeFlag (orangefs_inode); inode->i_mode = mode;mark_inode_dirty_sync (inode); -if (error ==0 ) - acl =NULL ; }break ;case ACL_TYPE_DEFAULT :
fs/posix_acl.c +31 -0
@@ -626,6 +626,37 @@ no_mem: }EXPORT_SYMBOL_GPL (posix_acl_create); +/** +* posix_acl_update_mode - update mode in set_acl +* +* Update the file mode when setting an ACL: compute the new file permission +* bits based on the ACL. In addition, if the ACL is equivalent to the new +* file mode, set *acl to NULL to indicate that no ACL should be set. +* +* As with chmod, clear the setgit bit if the caller is not in the owning group +* or capable of CAP_FSETID (see inode_change_ok). +* +* Called from set_acl inode operations. +*/ +int posix_acl_update_mode (struct inode *inode,umode_t *mode_p, +struct posix_acl **acl) +{ +umode_t mode = inode->i_mode; +int error; + + error =posix_acl_equiv_mode (*acl, &mode); +if (error <0 ) +return error; +if (error ==0 ) + *acl =NULL ; +if (!in_group_p (inode->i_gid) && + !capable_wrt_inode_uidgid (inode,CAP_FSETID )) + mode &= ~S_ISGID ; + *mode_p = mode; +return 0 ; +} +EXPORT_SYMBOL (posix_acl_update_mode); +/* * Fix up the uids and gids in posix acl extended attributes in place. */
fs/reiserfs/xattr_acl.c +2 -6
@@ -242,13 +242,9 @@ __reiserfs_set_acl(struct reiserfs_transcase ACL_TYPE_ACCESS : name =XATTR_NAME_POSIX_ACL_ACCESS ;if (acl) { - error =posix_acl_equiv_mode (acl, &inode->i_mode); -if (error <0 ) + error =posix_acl_update_mode (inode, &inode->i_mode, &acl); +if (error)return error; -else { -if (error ==0 ) - acl =NULL ; - } }break ;case ACL_TYPE_DEFAULT :
fs/xfs/xfs_acl.c +4 -9
@@ -257,16 +257,11 @@ xfs_set_acl(struct inode *inode, structreturn error;if (type ==ACL_TYPE_ACCESS ) { -umode_t mode = inode->i_mode; - error =posix_acl_equiv_mode (acl, &mode); - -if (error <=0 ) { - acl =NULL ; - -if (error <0 ) -return error; - } +umode_t mode; + error =posix_acl_update_mode (inode, &mode, &acl); +if (error) +return error; error =xfs_set_mode (inode, mode);if (error)return error;
include/linux/posix_acl.h +1 -0
@@ -93,6 +93,7 @@ extern int set_posix_acl(struct inode *,extern int posix_acl_chmod (struct inode *,umode_t );extern int posix_acl_create (struct inode *,umode_t *,struct posix_acl **,struct posix_acl **); +extern int posix_acl_update_mode (struct inode *,umode_t *,struct posix_acl **);extern int simple_set_acl (struct inode *,struct posix_acl *,int );extern int simple_acl_create (struct inode *,struct inode *);
Patches currently in stable-queue which might be from [email protected] are
queue-4.8/posix_acl-clear-sgid-bit-when-setting-file-permissions.patch