summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSona Sarmadi <sona.sarmadi@enea.com>2017-02-03 11:01:29 +0100
committerAdrian Dudau <adrian.dudau@enea.com>2017-02-06 10:45:26 +0100
commitff0bff80783d049ad584e9a0497350211770f138 (patch)
treea12f5305db185fc78db228f34ccf9e69f1d2067c
parent5027488b26d6102220ca2444aa73c03c035f0277 (diff)
downloadmeta-enea-bsp-ppc-ff0bff80783d049ad584e9a0497350211770f138.tar.gz
kernel: CVE-2016-7097
Setting a POSIX ACL via setxattr doesn't clear the setgid bit The filesystem implementation in the Linux kernel through 4.8.2 preserves the setgid bit during a setxattr call, which allows local users to gain group privileges by leveraging the existence of a setgid program with restrictions on execute permissions. Reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-7097 Reference to upstream commits (kernel.org 3.12 branch): https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/log/?id=refs%2Ftags%2Fv3.12.70&qt=grep&q=posix_acl%3A+Clear+SGID+bit+when+setting+file+permissions Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> Signed-off-by: Adrian Dudau <adrian.dudau@enea.com>
-rw-r--r--recipes-kernel/linux/files/0002-tmpfs-CVE-2016-7097.patch64
-rw-r--r--recipes-kernel/linux/files/tmpfs-CVE-2016-7097.patch440
-rw-r--r--recipes-kernel/linux/linux-qoriq_3.12.bbappend1
3 files changed, 505 insertions, 0 deletions
diff --git a/recipes-kernel/linux/files/0002-tmpfs-CVE-2016-7097.patch b/recipes-kernel/linux/files/0002-tmpfs-CVE-2016-7097.patch
new file mode 100644
index 0000000..7d8d429
--- /dev/null
+++ b/recipes-kernel/linux/files/0002-tmpfs-CVE-2016-7097.patch
@@ -0,0 +1,64 @@
1From b0369e53c851f8cd87afd059d360a4f646840c8c Mon Sep 17 00:00:00 2001
2From: Gu Zheng <guzheng1@huawei.com>
3Date: Mon, 9 Jan 2017 09:34:48 +0800
4Subject: tmpfs: clear S_ISGID when setting posix ACLs
5
6commit 497de07d89c1410d76a15bec2bb41f24a2a89f31 upstream.
7
8This change was missed the tmpfs modification in In CVE-2016-7097
9commit 073931017b49 ("posix_acl: Clear SGID bit when setting
10file permissions")
11It can test by xfstest generic/375, which failed to clear
12setgid bit in the following test case on tmpfs:
13
14 touch $testfile
15 chown 100:100 $testfile
16 chmod 2755 $testfile
17 _runas -u 100 -g 101 -- setfacl -m u::rwx,g::rwx,o::rwx $testfile
18
19CVE: CVE-2016-7097
20Upstream_status: backport
21
22Signed-off-by: Gu Zheng <guzheng1@huawei.com>
23Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
24Signed-off-by: Jan Kara <jack@suse.cz>
25Signed-off-by: Jiri Slaby <jslaby@suse.cz>
26Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
27---
28 fs/generic_acl.c | 12 +++++++-----
29 1 file changed, 7 insertions(+), 5 deletions(-)
30
31diff --git a/fs/generic_acl.c b/fs/generic_acl.c
32index b3f3676..7855cfb 100644
33--- a/fs/generic_acl.c
34+++ b/fs/generic_acl.c
35@@ -82,19 +82,21 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value,
36 return PTR_ERR(acl);
37 }
38 if (acl) {
39+ struct posix_acl *old_acl;
40+
41 error = posix_acl_valid(acl);
42 if (error)
43 goto failed;
44 switch (type) {
45 case ACL_TYPE_ACCESS:
46- error = posix_acl_equiv_mode(acl, &inode->i_mode);
47+ old_acl = acl;
48+ error = posix_acl_update_mode(inode, &inode->i_mode,
49+ &acl);
50 if (error < 0)
51 goto failed;
52+ if (!acl)
53+ posix_acl_release(old_acl);
54 inode->i_ctime = CURRENT_TIME;
55- if (error == 0) {
56- posix_acl_release(acl);
57- acl = NULL;
58- }
59 break;
60 case ACL_TYPE_DEFAULT:
61 if (!S_ISDIR(inode->i_mode)) {
62--
63cgit v0.12
64
diff --git a/recipes-kernel/linux/files/tmpfs-CVE-2016-7097.patch b/recipes-kernel/linux/files/tmpfs-CVE-2016-7097.patch
new file mode 100644
index 0000000..b11830c
--- /dev/null
+++ b/recipes-kernel/linux/files/tmpfs-CVE-2016-7097.patch
@@ -0,0 +1,440 @@
1From a88a2be387d1d8a5843826e12009c79e32fb46c8 Mon Sep 17 00:00:00 2001
2From: Jan Kara <jack@suse.cz>
3Date: Tue, 25 Oct 2016 08:44:26 -0500
4Subject: posix_acl: Clear SGID bit when setting file permissions
5
6commit 073931017b49d9458aa351605b43a7e34598caef upstream.
7
8When file permissions are modified via chmod(2) and the user is not in
9the owning group or capable of CAP_FSETID, the setgid bit is cleared in
10inode_change_ok(). Setting a POSIX ACL via setxattr(2) sets the file
11permissions as well as the new ACL, but doesn't clear the setgid bit in
12a similar way; this allows to bypass the check in chmod(2). Fix that.
13
14CVE: CVE-2016-7097
15Upstream-Status: Backport
16
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: Jiri Slaby <jslaby@suse.cz>
22Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
23---
24 fs/9p/acl.c | 40 +++++++++++++++++-----------------------
25 fs/btrfs/acl.c | 6 ++----
26 fs/ext2/acl.c | 12 ++++--------
27 fs/ext3/acl.c | 10 +++-------
28 fs/ext4/acl.c | 12 ++++--------
29 fs/f2fs/acl.c | 6 ++----
30 fs/gfs2/acl.c | 14 ++++++--------
31 fs/hfsplus/posix_acl.c | 4 ++--
32 fs/hfsplus/xattr.c | 5 +++--
33 fs/jffs2/acl.c | 9 ++++-----
34 fs/jfs/xattr.c | 5 +++--
35 fs/ocfs2/acl.c | 20 +++++++-------------
36 fs/posix_acl.c | 31 +++++++++++++++++++++++++++++++
37 fs/reiserfs/xattr_acl.c | 8 ++------
38 fs/xfs/xfs_acl.c | 15 +++++++--------
39 include/linux/posix_acl.h | 1 +
40 16 files changed, 98 insertions(+), 100 deletions(-)
41
42diff --git a/fs/9p/acl.c b/fs/9p/acl.c
43index 7af425f..9686c1f1 100644
44--- a/fs/9p/acl.c
45+++ b/fs/9p/acl.c
46@@ -320,32 +320,26 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
47 case ACL_TYPE_ACCESS:
48 name = POSIX_ACL_XATTR_ACCESS;
49 if (acl) {
50- umode_t mode = inode->i_mode;
51- retval = posix_acl_equiv_mode(acl, &mode);
52- if (retval < 0)
53+ struct iattr iattr;
54+
55+ retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
56+ if (retval)
57 goto err_out;
58- else {
59- struct iattr iattr;
60- if (retval == 0) {
61- /*
62- * ACL can be represented
63- * by the mode bits. So don't
64- * update ACL.
65- */
66- acl = NULL;
67- value = NULL;
68- size = 0;
69- }
70- /* Updte the mode bits */
71- iattr.ia_mode = ((mode & S_IALLUGO) |
72- (inode->i_mode & ~S_IALLUGO));
73- iattr.ia_valid = ATTR_MODE;
74- /* FIXME should we update ctime ?
75- * What is the following setxattr update the
76- * mode ?
77+ if (!acl) {
78+ /*
79+ * ACL can be represented
80+ * by the mode bits. So don't
81+ * update ACL.
82 */
83- v9fs_vfs_setattr_dotl(dentry, &iattr);
84+ value = NULL;
85+ size = 0;
86 }
87+ iattr.ia_valid = ATTR_MODE;
88+ /* FIXME should we update ctime ?
89+ * What is the following setxattr update the
90+ * mode ?
91+ */
92+ v9fs_vfs_setattr_dotl(dentry, &iattr);
93 }
94 break;
95 case ACL_TYPE_DEFAULT:
96diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
97index 0890c83..d6d53e5 100644
98--- a/fs/btrfs/acl.c
99+++ b/fs/btrfs/acl.c
100@@ -118,11 +118,9 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
101 case ACL_TYPE_ACCESS:
102 name = POSIX_ACL_XATTR_ACCESS;
103 if (acl) {
104- ret = posix_acl_equiv_mode(acl, &inode->i_mode);
105- if (ret < 0)
106+ ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
107+ if (ret)
108 return ret;
109- if (ret == 0)
110- acl = NULL;
111 }
112 ret = 0;
113 break;
114diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
115index 110b6b3..48c3c2d 100644
116--- a/fs/ext2/acl.c
117+++ b/fs/ext2/acl.c
118@@ -206,15 +206,11 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
119 case ACL_TYPE_ACCESS:
120 name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
121 if (acl) {
122- error = posix_acl_equiv_mode(acl, &inode->i_mode);
123- if (error < 0)
124+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
125+ if (error)
126 return error;
127- else {
128- inode->i_ctime = CURRENT_TIME_SEC;
129- mark_inode_dirty(inode);
130- if (error == 0)
131- acl = NULL;
132- }
133+ inode->i_ctime = CURRENT_TIME_SEC;
134+ mark_inode_dirty(inode);
135 }
136 break;
137
138diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
139index dbb5ad5..2f994bb 100644
140--- a/fs/ext3/acl.c
141+++ b/fs/ext3/acl.c
142@@ -205,15 +205,11 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
143 case ACL_TYPE_ACCESS:
144 name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
145 if (acl) {
146- error = posix_acl_equiv_mode(acl, &inode->i_mode);
147+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
148 if (error < 0)
149 return error;
150- else {
151- inode->i_ctime = CURRENT_TIME_SEC;
152- ext3_mark_inode_dirty(handle, inode);
153- if (error == 0)
154- acl = NULL;
155- }
156+ inode->i_ctime = CURRENT_TIME_SEC;
157+ ext3_mark_inode_dirty(handle, inode);
158 }
159 break;
160
161diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
162index 39a54a0..c844f1b 100644
163--- a/fs/ext4/acl.c
164+++ b/fs/ext4/acl.c
165@@ -211,15 +211,11 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
166 case ACL_TYPE_ACCESS:
167 name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
168 if (acl) {
169- error = posix_acl_equiv_mode(acl, &inode->i_mode);
170- if (error < 0)
171+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
172+ if (error)
173 return error;
174- else {
175- inode->i_ctime = ext4_current_time(inode);
176- ext4_mark_inode_dirty(handle, inode);
177- if (error == 0)
178- acl = NULL;
179- }
180+ inode->i_ctime = ext4_current_time(inode);
181+ ext4_mark_inode_dirty(handle, inode);
182 }
183 break;
184
185diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
186index b7826ec..f4fefc5 100644
187--- a/fs/f2fs/acl.c
188+++ b/fs/f2fs/acl.c
189@@ -223,12 +223,10 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
190 case ACL_TYPE_ACCESS:
191 name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
192 if (acl) {
193- error = posix_acl_equiv_mode(acl, &inode->i_mode);
194- if (error < 0)
195+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
196+ if (error)
197 return error;
198 set_acl_inode(fi, inode->i_mode);
199- if (error == 0)
200- acl = NULL;
201 }
202 break;
203
204diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
205index f69ac0a..a61b0c2 100644
206--- a/fs/gfs2/acl.c
207+++ b/fs/gfs2/acl.c
208@@ -268,15 +268,13 @@ static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,
209
210 if (type == ACL_TYPE_ACCESS) {
211 umode_t mode = inode->i_mode;
212- error = posix_acl_equiv_mode(acl, &mode);
213+ struct posix_acl *old_acl = acl;
214
215- if (error <= 0) {
216- posix_acl_release(acl);
217- acl = NULL;
218-
219- if (error < 0)
220- return error;
221- }
222+ error = posix_acl_update_mode(inode, &mode, &acl);
223+ if (error < 0)
224+ goto out_release;
225+ if (!acl)
226+ posix_acl_release(old_acl);
227
228 error = gfs2_set_mode(inode, mode);
229 if (error)
230diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
231index b609cc1..9f7cc49 100644
232--- a/fs/hfsplus/posix_acl.c
233+++ b/fs/hfsplus/posix_acl.c
234@@ -72,8 +72,8 @@ static int hfsplus_set_posix_acl(struct inode *inode,
235 case ACL_TYPE_ACCESS:
236 xattr_name = POSIX_ACL_XATTR_ACCESS;
237 if (acl) {
238- err = posix_acl_equiv_mode(acl, &inode->i_mode);
239- if (err < 0)
240+ err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
241+ if (err)
242 return err;
243 }
244 err = 0;
245diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
246index bd8471f..889be3f 100644
247--- a/fs/hfsplus/xattr.c
248+++ b/fs/hfsplus/xattr.c
249@@ -69,8 +69,9 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
250 if (IS_ERR(acl))
251 return PTR_ERR(acl);
252 if (acl) {
253- err = posix_acl_equiv_mode(acl, &inode->i_mode);
254- posix_acl_release(acl);
255+ struct posix_acl *old_acl = acl;
256+ err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
257+ posix_acl_release(old_acl);
258 if (err < 0)
259 return err;
260 mark_inode_dirty(inode);
261diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
262index 223283c..9335b8d 100644
263--- a/fs/jffs2/acl.c
264+++ b/fs/jffs2/acl.c
265@@ -243,9 +243,10 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
266 case ACL_TYPE_ACCESS:
267 xprefix = JFFS2_XPREFIX_ACL_ACCESS;
268 if (acl) {
269- umode_t mode = inode->i_mode;
270- rc = posix_acl_equiv_mode(acl, &mode);
271- if (rc < 0)
272+ umode_t mode;
273+
274+ rc = posix_acl_update_mode(inode, &mode, &acl);
275+ if (rc)
276 return rc;
277 if (inode->i_mode != mode) {
278 struct iattr attr;
279@@ -257,8 +258,6 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
280 if (rc < 0)
281 return rc;
282 }
283- if (rc == 0)
284- acl = NULL;
285 }
286 break;
287 case ACL_TYPE_DEFAULT:
288diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
289index d3472f4..8c9b6a0 100644
290--- a/fs/jfs/xattr.c
291+++ b/fs/jfs/xattr.c
292@@ -693,8 +693,9 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
293 return rc;
294 }
295 if (acl) {
296- rc = posix_acl_equiv_mode(acl, &inode->i_mode);
297- posix_acl_release(acl);
298+ struct posix_acl *old_acl = acl;
299+ rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
300+ posix_acl_release(old_acl);
301 if (rc < 0) {
302 printk(KERN_ERR
303 "posix_acl_equiv_mode returned %d\n",
304diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
305index b4f788e..23095b0 100644
306--- a/fs/ocfs2/acl.c
307+++ b/fs/ocfs2/acl.c
308@@ -270,20 +270,14 @@ static int ocfs2_set_acl(handle_t *handle,
309 case ACL_TYPE_ACCESS:
310 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
311 if (acl) {
312- umode_t mode = inode->i_mode;
313- ret = posix_acl_equiv_mode(acl, &mode);
314- if (ret < 0)
315+ umode_t mode;
316+ ret = posix_acl_update_mode(inode, &mode, &acl);
317+ if (ret)
318+ return ret;
319+ ret = ocfs2_acl_set_mode(inode, di_bh,
320+ handle, mode);
321+ if (ret)
322 return ret;
323- else {
324- if (ret == 0)
325- acl = NULL;
326-
327- ret = ocfs2_acl_set_mode(inode, di_bh,
328- handle, mode);
329- if (ret)
330- return ret;
331-
332- }
333 }
334 break;
335 case ACL_TYPE_DEFAULT:
336diff --git a/fs/posix_acl.c b/fs/posix_acl.c
337index 3542f1f..1da000a 100644
338--- a/fs/posix_acl.c
339+++ b/fs/posix_acl.c
340@@ -407,6 +407,37 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
341 }
342 EXPORT_SYMBOL(posix_acl_create);
343
344+/**
345+ * posix_acl_update_mode - update mode in set_acl
346+ *
347+ * Update the file mode when setting an ACL: compute the new file permission
348+ * bits based on the ACL. In addition, if the ACL is equivalent to the new
349+ * file mode, set *acl to NULL to indicate that no ACL should be set.
350+ *
351+ * As with chmod, clear the setgit bit if the caller is not in the owning group
352+ * or capable of CAP_FSETID (see inode_change_ok).
353+ *
354+ * Called from set_acl inode operations.
355+ */
356+int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
357+ struct posix_acl **acl)
358+{
359+ umode_t mode = inode->i_mode;
360+ int error;
361+
362+ error = posix_acl_equiv_mode(*acl, &mode);
363+ if (error < 0)
364+ return error;
365+ if (error == 0)
366+ *acl = NULL;
367+ if (!in_group_p(inode->i_gid) &&
368+ !capable_wrt_inode_uidgid(inode, CAP_FSETID))
369+ mode &= ~S_ISGID;
370+ *mode_p = mode;
371+ return 0;
372+}
373+EXPORT_SYMBOL(posix_acl_update_mode);
374+
375 int
376 posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
377 {
378diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
379index 06c04f7..a86ad7e 100644
380--- a/fs/reiserfs/xattr_acl.c
381+++ b/fs/reiserfs/xattr_acl.c
382@@ -288,13 +288,9 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
383 case ACL_TYPE_ACCESS:
384 name = POSIX_ACL_XATTR_ACCESS;
385 if (acl) {
386- error = posix_acl_equiv_mode(acl, &inode->i_mode);
387- if (error < 0)
388+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
389+ if (error)
390 return error;
391- else {
392- if (error == 0)
393- acl = NULL;
394- }
395 }
396 break;
397 case ACL_TYPE_DEFAULT:
398diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
399index 0e2f37e..9c7b5ce 100644
400--- a/fs/xfs/xfs_acl.c
401+++ b/fs/xfs/xfs_acl.c
402@@ -402,16 +402,15 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
403 goto out_release;
404
405 if (type == ACL_TYPE_ACCESS) {
406- umode_t mode = inode->i_mode;
407- error = posix_acl_equiv_mode(acl, &mode);
408+ umode_t mode;
409+ struct posix_acl *old_acl = acl;
410
411- if (error <= 0) {
412- posix_acl_release(acl);
413- acl = NULL;
414+ error = posix_acl_update_mode(inode, &mode, &acl);
415
416- if (error < 0)
417- return error;
418- }
419+ if (error)
420+ goto out_release;
421+ if (!acl)
422+ posix_acl_release(old_acl);
423
424 error = xfs_set_mode(inode, mode);
425 if (error)
426diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
427index 7931efe..43cb8d5 100644
428--- a/include/linux/posix_acl.h
429+++ b/include/linux/posix_acl.h
430@@ -89,6 +89,7 @@ extern int posix_acl_permission(struct inode *, const struct posix_acl *, int);
431 extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t);
432 extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *);
433 extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
434+extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
435 extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
436
437 extern struct posix_acl *get_posix_acl(struct inode *, int);
438--
439cgit v0.12
440
diff --git a/recipes-kernel/linux/linux-qoriq_3.12.bbappend b/recipes-kernel/linux/linux-qoriq_3.12.bbappend
index be8cf93..7689676 100644
--- a/recipes-kernel/linux/linux-qoriq_3.12.bbappend
+++ b/recipes-kernel/linux/linux-qoriq_3.12.bbappend
@@ -10,5 +10,6 @@ SRC_URI += "file://ppp-CVE-2015-8569.patch \
10 file://CVE-2016-5195.patch \ 10 file://CVE-2016-5195.patch \
11 file://CVE-2016-6480.patch \ 11 file://CVE-2016-6480.patch \
12 file://ring-buffer-CVE-2016-9754.patch \ 12 file://ring-buffer-CVE-2016-9754.patch \
13 file://tmpfs-CVE-2016-7097.patch \
13 " 14 "
14 15