From: Greg Kroah-Hartman Date: Fri, 28 Oct 2016 15:41:29 +0000 (-0400) Subject: 4.8-stable patches X-Git-Tag: v4.4.29~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=918c086c8495b24da9a39a8ad539351d719c308b;p=thirdparty%2Fkernel%2Fstable-queue.git 4.8-stable patches added patches: posix_acl-clear-sgid-bit-when-setting-file-permissions.patch --- diff --git a/queue-4.8/posix_acl-clear-sgid-bit-when-setting-file-permissions.patch b/queue-4.8/posix_acl-clear-sgid-bit-when-setting-file-permissions.patch new file mode 100644 index 00000000000..f5d12375ec2 --- /dev/null +++ b/queue-4.8/posix_acl-clear-sgid-bit-when-setting-file-permissions.patch @@ -0,0 +1,408 @@ +From 073931017b49d9458aa351605b43a7e34598caef Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Mon, 19 Sep 2016 17:39:09 +0200 +Subject: posix_acl: Clear SGID bit when setting file permissions + +From: Jan Kara + +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 +Reviewed-by: Christoph Hellwig +Reviewed-by: Jeff Layton +Signed-off-by: Jan Kara +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Juerg Haefliger +Signed-off-by: Greg Kroah-Hartman + +--- + 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(-) + +--- a/fs/9p/acl.c ++++ b/fs/9p/acl.c +@@ -276,32 +276,26 @@ static int v9fs_xattr_set_acl(const stru + switch (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: +--- a/fs/btrfs/acl.c ++++ b/fs/btrfs/acl.c +@@ -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; +--- a/fs/ceph/acl.c ++++ b/fs/ceph/acl.c +@@ -95,11 +95,9 @@ int ceph_set_acl(struct inode *inode, st + case 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: +--- a/fs/ext2/acl.c ++++ b/fs/ext2/acl.c +@@ -190,15 +190,11 @@ ext2_set_acl(struct inode *inode, struct + case 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; + +--- a/fs/ext4/acl.c ++++ b/fs/ext4/acl.c +@@ -193,15 +193,11 @@ __ext4_set_acl(handle_t *handle, struct + case 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; + +--- a/fs/f2fs/acl.c ++++ b/fs/f2fs/acl.c +@@ -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; + +--- a/fs/gfs2/acl.c ++++ b/fs/gfs2/acl.c +@@ -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) { +--- a/fs/hfsplus/posix_acl.c ++++ b/fs/hfsplus/posix_acl.c +@@ -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; +--- a/fs/jffs2/acl.c ++++ b/fs/jffs2/acl.c +@@ -233,9 +233,10 @@ int jffs2_set_acl(struct inode *inode, s + case 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, s + if (rc < 0) + return rc; + } +- if (rc == 0) +- acl = NULL; + } + break; + case ACL_TYPE_DEFAULT: +--- a/fs/jfs/acl.c ++++ b/fs/jfs/acl.c +@@ -78,13 +78,11 @@ static int __jfs_set_acl(tid_t tid, stru + case 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: +--- a/fs/ocfs2/acl.c ++++ b/fs/ocfs2/acl.c +@@ -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); +--- a/fs/orangefs/acl.c ++++ b/fs/orangefs/acl.c +@@ -73,14 +73,11 @@ int orangefs_set_acl(struct inode *inode + case 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 *inode + SetModeFlag(orangefs_inode); + inode->i_mode = mode; + mark_inode_dirty_sync(inode); +- if (error == 0) +- acl = NULL; + } + break; + case ACL_TYPE_DEFAULT: +--- a/fs/posix_acl.c ++++ b/fs/posix_acl.c +@@ -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. + */ +--- a/fs/reiserfs/xattr_acl.c ++++ b/fs/reiserfs/xattr_acl.c +@@ -242,13 +242,9 @@ __reiserfs_set_acl(struct reiserfs_trans + case 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: +--- a/fs/xfs/xfs_acl.c ++++ b/fs/xfs/xfs_acl.c +@@ -257,16 +257,11 @@ xfs_set_acl(struct inode *inode, struct + return 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; +--- a/include/linux/posix_acl.h ++++ b/include/linux/posix_acl.h +@@ -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 *); diff --git a/queue-4.8/series b/queue-4.8/series index 26cf8fb4314..5cef7878f54 100644 --- a/queue-4.8/series +++ b/queue-4.8/series @@ -36,3 +36,4 @@ drm-i915-move-long-hpd-handling-into-the-hotplug-work.patch drm-i915-allow-dp-to-work-w-o-edid.patch drm-i915-just-clear-the-mmiodebug-before-a-register-access.patch drm-i915-unalias-obj-phys_handle-and-obj-userptr.patch +posix_acl-clear-sgid-bit-when-setting-file-permissions.patch