]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.4.29/posix_acl-clear-sgid-bit-when-setting-file-permissions.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.4.29 / posix_acl-clear-sgid-bit-when-setting-file-permissions.patch
CommitLineData
4227f6b8
GKH
1From 073931017b49d9458aa351605b43a7e34598caef Mon Sep 17 00:00:00 2001
2From: Jan Kara <jack@suse.cz>
3Date: Mon, 19 Sep 2016 17:39:09 +0200
4Subject: posix_acl: Clear SGID bit when setting file permissions
5
6From: Jan Kara <jack@suse.cz>
7
8commit 073931017b49d9458aa351605b43a7e34598caef upstream.
9
10When file permissions are modified via chmod(2) and the user is not in
11the owning group or capable of CAP_FSETID, the setgid bit is cleared in
12inode_change_ok(). Setting a POSIX ACL via setxattr(2) sets the file
13permissions as well as the new ACL, but doesn't clear the setgid bit in
14a similar way; this allows to bypass the check in chmod(2). Fix that.
15
16References: CVE-2016-7097
17Reviewed-by: Christoph Hellwig <hch@lst.de>
18Reviewed-by: Jeff Layton <jlayton@redhat.com>
19Signed-off-by: Jan Kara <jack@suse.cz>
20Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
21Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
22
23---
24 fs/9p/acl.c | 40 +++++++++++++++++-----------------------
25 fs/btrfs/acl.c | 6 ++----
26 fs/ceph/acl.c | 6 ++----
27 fs/ext2/acl.c | 12 ++++--------
28 fs/ext4/acl.c | 12 ++++--------
29 fs/f2fs/acl.c | 6 ++----
30 fs/gfs2/acl.c | 12 +++---------
31 fs/hfsplus/posix_acl.c | 4 ++--
32 fs/jffs2/acl.c | 9 ++++-----
33 fs/jfs/acl.c | 6 ++----
34 fs/ocfs2/acl.c | 10 ++++------
35 fs/posix_acl.c | 31 +++++++++++++++++++++++++++++++
36 fs/reiserfs/xattr_acl.c | 8 ++------
37 fs/xfs/xfs_acl.c | 13 ++++---------
38 include/linux/posix_acl.h | 1 +
39 15 files changed, 84 insertions(+), 92 deletions(-)
40
41--- a/fs/9p/acl.c
42+++ b/fs/9p/acl.c
43@@ -282,32 +282,26 @@ static int v9fs_xattr_set_acl(const stru
44 switch (handler->flags) {
45 case ACL_TYPE_ACCESS:
46 if (acl) {
47- umode_t mode = inode->i_mode;
48- retval = posix_acl_equiv_mode(acl, &mode);
49- if (retval < 0)
50+ struct iattr iattr;
51+
52+ retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
53+ if (retval)
54 goto err_out;
55- else {
56- struct iattr iattr;
57- if (retval == 0) {
58- /*
59- * ACL can be represented
60- * by the mode bits. So don't
61- * update ACL.
62- */
63- acl = NULL;
64- value = NULL;
65- size = 0;
66- }
67- /* Updte the mode bits */
68- iattr.ia_mode = ((mode & S_IALLUGO) |
69- (inode->i_mode & ~S_IALLUGO));
70- iattr.ia_valid = ATTR_MODE;
71- /* FIXME should we update ctime ?
72- * What is the following setxattr update the
73- * mode ?
74+ if (!acl) {
75+ /*
76+ * ACL can be represented
77+ * by the mode bits. So don't
78+ * update ACL.
79 */
80- v9fs_vfs_setattr_dotl(dentry, &iattr);
81+ value = NULL;
82+ size = 0;
83 }
84+ iattr.ia_valid = ATTR_MODE;
85+ /* FIXME should we update ctime ?
86+ * What is the following setxattr update the
87+ * mode ?
88+ */
89+ v9fs_vfs_setattr_dotl(dentry, &iattr);
90 }
91 break;
92 case ACL_TYPE_DEFAULT:
93--- a/fs/btrfs/acl.c
94+++ b/fs/btrfs/acl.c
95@@ -83,11 +83,9 @@ static int __btrfs_set_acl(struct btrfs_
96 case ACL_TYPE_ACCESS:
97 name = POSIX_ACL_XATTR_ACCESS;
98 if (acl) {
99- ret = posix_acl_equiv_mode(acl, &inode->i_mode);
100- if (ret < 0)
101+ ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
102+ if (ret)
103 return ret;
104- if (ret == 0)
105- acl = NULL;
106 }
107 ret = 0;
108 break;
109--- a/fs/ceph/acl.c
110+++ b/fs/ceph/acl.c
111@@ -94,11 +94,9 @@ int ceph_set_acl(struct inode *inode, st
112 case ACL_TYPE_ACCESS:
113 name = POSIX_ACL_XATTR_ACCESS;
114 if (acl) {
115- ret = posix_acl_equiv_mode(acl, &new_mode);
116- if (ret < 0)
117+ ret = posix_acl_update_mode(inode, &new_mode, &acl);
118+ if (ret)
119 goto out;
120- if (ret == 0)
121- acl = NULL;
122 }
123 break;
124 case ACL_TYPE_DEFAULT:
125--- a/fs/ext2/acl.c
126+++ b/fs/ext2/acl.c
127@@ -193,15 +193,11 @@ ext2_set_acl(struct inode *inode, struct
128 case ACL_TYPE_ACCESS:
129 name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
130 if (acl) {
131- error = posix_acl_equiv_mode(acl, &inode->i_mode);
132- if (error < 0)
133+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
134+ if (error)
135 return error;
136- else {
137- inode->i_ctime = CURRENT_TIME_SEC;
138- mark_inode_dirty(inode);
139- if (error == 0)
140- acl = NULL;
141- }
142+ inode->i_ctime = CURRENT_TIME_SEC;
143+ mark_inode_dirty(inode);
144 }
145 break;
146
147--- a/fs/ext4/acl.c
148+++ b/fs/ext4/acl.c
149@@ -196,15 +196,11 @@ __ext4_set_acl(handle_t *handle, struct
150 case ACL_TYPE_ACCESS:
151 name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
152 if (acl) {
153- error = posix_acl_equiv_mode(acl, &inode->i_mode);
154- if (error < 0)
155+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
156+ if (error)
157 return error;
158- else {
159- inode->i_ctime = ext4_current_time(inode);
160- ext4_mark_inode_dirty(handle, inode);
161- if (error == 0)
162- acl = NULL;
163- }
164+ inode->i_ctime = ext4_current_time(inode);
165+ ext4_mark_inode_dirty(handle, inode);
166 }
167 break;
168
169--- a/fs/f2fs/acl.c
170+++ b/fs/f2fs/acl.c
171@@ -214,12 +214,10 @@ static int __f2fs_set_acl(struct inode *
172 case ACL_TYPE_ACCESS:
173 name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
174 if (acl) {
175- error = posix_acl_equiv_mode(acl, &inode->i_mode);
176- if (error < 0)
177+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
178+ if (error)
179 return error;
180 set_acl_inode(fi, inode->i_mode);
181- if (error == 0)
182- acl = NULL;
183 }
184 break;
185
186--- a/fs/gfs2/acl.c
187+++ b/fs/gfs2/acl.c
188@@ -79,17 +79,11 @@ int gfs2_set_acl(struct inode *inode, st
189 if (type == ACL_TYPE_ACCESS) {
190 umode_t mode = inode->i_mode;
191
192- error = posix_acl_equiv_mode(acl, &mode);
193- if (error < 0)
194+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
195+ if (error)
196 return error;
197-
198- if (error == 0)
199- acl = NULL;
200-
201- if (mode != inode->i_mode) {
202- inode->i_mode = mode;
203+ if (mode != inode->i_mode)
204 mark_inode_dirty(inode);
205- }
206 }
207
208 if (acl) {
209--- a/fs/hfsplus/posix_acl.c
210+++ b/fs/hfsplus/posix_acl.c
211@@ -68,8 +68,8 @@ int hfsplus_set_posix_acl(struct inode *
212 case ACL_TYPE_ACCESS:
213 xattr_name = POSIX_ACL_XATTR_ACCESS;
214 if (acl) {
215- err = posix_acl_equiv_mode(acl, &inode->i_mode);
216- if (err < 0)
217+ err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
218+ if (err)
219 return err;
220 }
221 err = 0;
222--- a/fs/jffs2/acl.c
223+++ b/fs/jffs2/acl.c
224@@ -235,9 +235,10 @@ int jffs2_set_acl(struct inode *inode, s
225 case ACL_TYPE_ACCESS:
226 xprefix = JFFS2_XPREFIX_ACL_ACCESS;
227 if (acl) {
228- umode_t mode = inode->i_mode;
229- rc = posix_acl_equiv_mode(acl, &mode);
230- if (rc < 0)
231+ umode_t mode;
232+
233+ rc = posix_acl_update_mode(inode, &mode, &acl);
234+ if (rc)
235 return rc;
236 if (inode->i_mode != mode) {
237 struct iattr attr;
238@@ -249,8 +250,6 @@ int jffs2_set_acl(struct inode *inode, s
239 if (rc < 0)
240 return rc;
241 }
242- if (rc == 0)
243- acl = NULL;
244 }
245 break;
246 case ACL_TYPE_DEFAULT:
247--- a/fs/jfs/acl.c
248+++ b/fs/jfs/acl.c
249@@ -84,13 +84,11 @@ static int __jfs_set_acl(tid_t tid, stru
250 case ACL_TYPE_ACCESS:
251 ea_name = POSIX_ACL_XATTR_ACCESS;
252 if (acl) {
253- rc = posix_acl_equiv_mode(acl, &inode->i_mode);
254- if (rc < 0)
255+ rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
256+ if (rc)
257 return rc;
258 inode->i_ctime = CURRENT_TIME;
259 mark_inode_dirty(inode);
260- if (rc == 0)
261- acl = NULL;
262 }
263 break;
264 case ACL_TYPE_DEFAULT:
265--- a/fs/ocfs2/acl.c
266+++ b/fs/ocfs2/acl.c
267@@ -241,13 +241,11 @@ int ocfs2_set_acl(handle_t *handle,
268 case ACL_TYPE_ACCESS:
269 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
270 if (acl) {
271- umode_t mode = inode->i_mode;
272- ret = posix_acl_equiv_mode(acl, &mode);
273- if (ret < 0)
274- return ret;
275+ umode_t mode;
276
277- if (ret == 0)
278- acl = NULL;
279+ ret = posix_acl_update_mode(inode, &mode, &acl);
280+ if (ret)
281+ return ret;
282
283 ret = ocfs2_acl_set_mode(inode, di_bh,
284 handle, mode);
285--- a/fs/posix_acl.c
286+++ b/fs/posix_acl.c
287@@ -592,6 +592,37 @@ no_mem:
288 }
289 EXPORT_SYMBOL_GPL(posix_acl_create);
290
291+/**
292+ * posix_acl_update_mode - update mode in set_acl
293+ *
294+ * Update the file mode when setting an ACL: compute the new file permission
295+ * bits based on the ACL. In addition, if the ACL is equivalent to the new
296+ * file mode, set *acl to NULL to indicate that no ACL should be set.
297+ *
298+ * As with chmod, clear the setgit bit if the caller is not in the owning group
299+ * or capable of CAP_FSETID (see inode_change_ok).
300+ *
301+ * Called from set_acl inode operations.
302+ */
303+int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
304+ struct posix_acl **acl)
305+{
306+ umode_t mode = inode->i_mode;
307+ int error;
308+
309+ error = posix_acl_equiv_mode(*acl, &mode);
310+ if (error < 0)
311+ return error;
312+ if (error == 0)
313+ *acl = NULL;
314+ if (!in_group_p(inode->i_gid) &&
315+ !capable_wrt_inode_uidgid(inode, CAP_FSETID))
316+ mode &= ~S_ISGID;
317+ *mode_p = mode;
318+ return 0;
319+}
320+EXPORT_SYMBOL(posix_acl_update_mode);
321+
322 /*
323 * Fix up the uids and gids in posix acl extended attributes in place.
324 */
325--- a/fs/reiserfs/xattr_acl.c
326+++ b/fs/reiserfs/xattr_acl.c
327@@ -246,13 +246,9 @@ __reiserfs_set_acl(struct reiserfs_trans
328 case ACL_TYPE_ACCESS:
329 name = POSIX_ACL_XATTR_ACCESS;
330 if (acl) {
331- error = posix_acl_equiv_mode(acl, &inode->i_mode);
332- if (error < 0)
333+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
334+ if (error)
335 return error;
336- else {
337- if (error == 0)
338- acl = NULL;
339- }
340 }
341 break;
342 case ACL_TYPE_DEFAULT:
343--- a/fs/xfs/xfs_acl.c
344+++ b/fs/xfs/xfs_acl.c
345@@ -288,16 +288,11 @@ xfs_set_acl(struct inode *inode, struct
346 return error;
347
348 if (type == ACL_TYPE_ACCESS) {
349- umode_t mode = inode->i_mode;
350- error = posix_acl_equiv_mode(acl, &mode);
351-
352- if (error <= 0) {
353- acl = NULL;
354-
355- if (error < 0)
356- return error;
357- }
358+ umode_t mode;
359
360+ error = posix_acl_update_mode(inode, &mode, &acl);
361+ if (error)
362+ return error;
363 error = xfs_set_mode(inode, mode);
364 if (error)
365 return error;
366--- a/include/linux/posix_acl.h
367+++ b/include/linux/posix_acl.h
368@@ -95,6 +95,7 @@ extern int set_posix_acl(struct inode *,
369 extern int posix_acl_chmod(struct inode *, umode_t);
370 extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
371 struct posix_acl **);
372+extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
373
374 extern int simple_set_acl(struct inode *, struct posix_acl *, int);
375 extern int simple_acl_create(struct inode *, struct inode *);