--- /dev/null
+From a3bb2d5587521eea6dab2d05326abb0afb460abd Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Sun, 30 Jul 2017 23:33:01 -0400
+Subject: ext4: Don't clear SGID when inheriting ACLs
+
+From: Jan Kara <jack@suse.cz>
+
+commit a3bb2d5587521eea6dab2d05326abb0afb460abd upstream.
+
+When new directory 'DIR1' is created in a directory 'DIR0' with SGID bit
+set, DIR1 is expected to have SGID bit set (and owning group equal to
+the owning group of 'DIR0'). However when 'DIR0' also has some default
+ACLs that 'DIR1' inherits, setting these ACLs will result in SGID bit on
+'DIR1' to get cleared if user is not member of the owning group.
+
+Fix the problem by moving posix_acl_update_mode() out of
+__ext4_set_acl() into ext4_set_acl(). That way the function will not be
+called when inheriting ACLs which is what we want as it prevents SGID
+bit clearing and the mode has been properly set by posix_acl_create()
+anyway.
+
+Fixes: 073931017b49d9458aa351605b43a7e34598caef
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ext4/acl.c | 28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+--- a/fs/ext4/acl.c
++++ b/fs/ext4/acl.c
+@@ -189,18 +189,10 @@ __ext4_set_acl(handle_t *handle, struct
+ void *value = NULL;
+ size_t size = 0;
+ int error;
+- int update_mode = 0;
+- umode_t mode = inode->i_mode;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
+- if (acl) {
+- error = posix_acl_update_mode(inode, &mode, &acl);
+- if (error)
+- return error;
+- update_mode = 1;
+- }
+ break;
+
+ case ACL_TYPE_DEFAULT:
+@@ -224,11 +216,6 @@ __ext4_set_acl(handle_t *handle, struct
+ kfree(value);
+ if (!error) {
+ set_cached_acl(inode, type, acl);
+- if (update_mode) {
+- inode->i_mode = mode;
+- inode->i_ctime = current_time(inode);
+- ext4_mark_inode_dirty(handle, inode);
+- }
+ }
+
+ return error;
+@@ -239,6 +226,8 @@ ext4_set_acl(struct inode *inode, struct
+ {
+ handle_t *handle;
+ int error, retries = 0;
++ umode_t mode = inode->i_mode;
++ int update_mode = 0;
+
+ error = dquot_initialize(inode);
+ if (error)
+@@ -249,7 +238,20 @@ retry:
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
++ if ((type == ACL_TYPE_ACCESS) && acl) {
++ error = posix_acl_update_mode(inode, &mode, &acl);
++ if (error)
++ goto out_stop;
++ update_mode = 1;
++ }
++
+ error = __ext4_set_acl(handle, inode, type, acl);
++ if (!error && update_mode) {
++ inode->i_mode = mode;
++ inode->i_ctime = current_time(inode);
++ ext4_mark_inode_dirty(handle, inode);
++ }
++out_stop:
+ ext4_journal_stop(handle);
+ if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
--- /dev/null
+From 397e434176bb62bc6068d2210af1d876c6212a7e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ernesto=20A=2E=20Fern=C3=A1ndez?= <ernesto.mnd.fernandez@gmail.com>
+Date: Sun, 30 Jul 2017 22:43:41 -0400
+Subject: ext4: preserve i_mode if __ext4_set_acl() fails
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
+
+commit 397e434176bb62bc6068d2210af1d876c6212a7e upstream.
+
+When changing a file's acl mask, __ext4_set_acl() will first set the group
+bits of i_mode to the value of the mask, and only then set the actual
+extended attribute representing the new acl.
+
+If the second part fails (due to lack of space, for example) and the file
+had no acl attribute to begin with, the system will from now on assume
+that the mask permission bits are actual group permission bits, potentially
+granting access to the wrong users.
+
+Prevent this by only changing the inode mode after the acl has been set.
+
+Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ext4/acl.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+--- a/fs/ext4/acl.c
++++ b/fs/ext4/acl.c
+@@ -189,16 +189,17 @@ __ext4_set_acl(handle_t *handle, struct
+ void *value = NULL;
+ size_t size = 0;
+ int error;
++ int update_mode = 0;
++ umode_t mode = inode->i_mode;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
+ if (acl) {
+- error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
++ error = posix_acl_update_mode(inode, &mode, &acl);
+ if (error)
+ return error;
+- inode->i_ctime = current_time(inode);
+- ext4_mark_inode_dirty(handle, inode);
++ update_mode = 1;
+ }
+ break;
+
+@@ -221,8 +222,14 @@ __ext4_set_acl(handle_t *handle, struct
+ value, size, 0);
+
+ kfree(value);
+- if (!error)
++ if (!error) {
+ set_cached_acl(inode, type, acl);
++ if (update_mode) {
++ inode->i_mode = mode;
++ inode->i_ctime = current_time(inode);
++ ext4_mark_inode_dirty(handle, inode);
++ }
++ }
+
+ return error;
+ }