Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gfs2: preserve i_mode if __gfs2_set_acl() fails

When changing a file's acl mask, __gfs2_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: Bob Peterson <rpeterso@redhat.com>

authored by

Ernesto A. Fernández and committed by
Bob Peterson
309e8cda 54aae14b

+8 -5
+8 -5
fs/gfs2/acl.c
··· 116 116 struct gfs2_holder gh; 117 117 bool need_unlock = false; 118 118 int ret; 119 + umode_t mode; 119 120 120 121 if (acl && acl->a_count > GFS2_ACL_MAX_ENTRIES(GFS2_SB(inode))) 121 122 return -E2BIG; ··· 131 130 return ret; 132 131 need_unlock = true; 133 132 } 134 - if (type == ACL_TYPE_ACCESS && acl) { 135 - umode_t mode = inode->i_mode; 136 133 137 - ret = posix_acl_update_mode(inode, &inode->i_mode, &acl); 134 + mode = inode->i_mode; 135 + if (type == ACL_TYPE_ACCESS && acl) { 136 + ret = posix_acl_update_mode(inode, &mode, &acl); 138 137 if (ret) 139 138 goto unlock; 140 - if (mode != inode->i_mode) 141 - mark_inode_dirty(inode); 142 139 } 143 140 144 141 ret = __gfs2_set_acl(inode, acl, type); 142 + if (!ret && mode != inode->i_mode) { 143 + inode->i_mode = mode; 144 + mark_inode_dirty(inode); 145 + } 145 146 unlock: 146 147 if (need_unlock) 147 148 gfs2_glock_dq_uninit(&gh);