hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
kernel/fs/attr.c
....@@ -18,6 +18,65 @@
1818 #include <linux/evm.h>
1919 #include <linux/ima.h>
2020
21
+#include "internal.h"
22
+
23
+/**
24
+ * setattr_should_drop_sgid - determine whether the setgid bit needs to be
25
+ * removed
26
+ * @inode: inode to check
27
+ *
28
+ * This function determines whether the setgid bit needs to be removed.
29
+ * We retain backwards compatibility and require setgid bit to be removed
30
+ * unconditionally if S_IXGRP is set. Otherwise we have the exact same
31
+ * requirements as setattr_prepare() and setattr_copy().
32
+ *
33
+ * Return: ATTR_KILL_SGID if setgid bit needs to be removed, 0 otherwise.
34
+ */
35
+int setattr_should_drop_sgid(const struct inode *inode)
36
+{
37
+ umode_t mode = inode->i_mode;
38
+
39
+ if (!(mode & S_ISGID))
40
+ return 0;
41
+ if (mode & S_IXGRP)
42
+ return ATTR_KILL_SGID;
43
+ if (!in_group_or_capable(inode, inode->i_gid))
44
+ return ATTR_KILL_SGID;
45
+ return 0;
46
+}
47
+
48
+/**
49
+ * setattr_should_drop_suidgid - determine whether the set{g,u}id bit needs to
50
+ * be dropped
51
+ * @inode: inode to check
52
+ *
53
+ * This function determines whether the set{g,u}id bits need to be removed.
54
+ * If the setuid bit needs to be removed ATTR_KILL_SUID is returned. If the
55
+ * setgid bit needs to be removed ATTR_KILL_SGID is returned. If both
56
+ * set{g,u}id bits need to be removed the corresponding mask of both flags is
57
+ * returned.
58
+ *
59
+ * Return: A mask of ATTR_KILL_S{G,U}ID indicating which - if any - setid bits
60
+ * to remove, 0 otherwise.
61
+ */
62
+int setattr_should_drop_suidgid(struct inode *inode)
63
+{
64
+ umode_t mode = inode->i_mode;
65
+ int kill = 0;
66
+
67
+ /* suid always must be killed */
68
+ if (unlikely(mode & S_ISUID))
69
+ kill = ATTR_KILL_SUID;
70
+
71
+ kill |= setattr_should_drop_sgid(inode);
72
+
73
+ if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
74
+ return kill;
75
+
76
+ return 0;
77
+}
78
+EXPORT_SYMBOL(setattr_should_drop_suidgid);
79
+
2180 static bool chown_ok(const struct inode *inode, kuid_t uid)
2281 {
2382 if (uid_eq(current_fsuid(), inode->i_uid) &&
....@@ -90,9 +149,8 @@
90149 if (!inode_owner_or_capable(inode))
91150 return -EPERM;
92151 /* Also check the setgid bit! */
93
- if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
94
- inode->i_gid) &&
95
- !capable_wrt_inode_uidgid(inode, CAP_FSETID))
152
+ if (!in_group_or_capable(inode, (ia_valid & ATTR_GID) ?
153
+ attr->ia_gid : inode->i_gid))
96154 attr->ia_mode &= ~S_ISGID;
97155 }
98156
....@@ -193,9 +251,7 @@
193251 inode->i_ctime = attr->ia_ctime;
194252 if (ia_valid & ATTR_MODE) {
195253 umode_t mode = attr->ia_mode;
196
-
197
- if (!in_group_p(inode->i_gid) &&
198
- !capable_wrt_inode_uidgid(inode, CAP_FSETID))
254
+ if (!in_group_or_capable(inode, inode->i_gid))
199255 mode &= ~S_ISGID;
200256 inode->i_mode = mode;
201257 }
....@@ -253,9 +309,25 @@
253309 }
254310
255311 if ((ia_valid & ATTR_MODE)) {
256
- umode_t amode = attr->ia_mode;
312
+ /*
313
+ * Don't allow changing the mode of symlinks:
314
+ *
315
+ * (1) The vfs doesn't take the mode of symlinks into account
316
+ * during permission checking.
317
+ * (2) This has never worked correctly. Most major filesystems
318
+ * did return EOPNOTSUPP due to interactions with POSIX ACLs
319
+ * but did still updated the mode of the symlink.
320
+ * This inconsistency led system call wrapper providers such
321
+ * as libc to block changing the mode of symlinks with
322
+ * EOPNOTSUPP already.
323
+ * (3) To even do this in the first place one would have to use
324
+ * specific file descriptors and quite some effort.
325
+ */
326
+ if (S_ISLNK(inode->i_mode))
327
+ return -EOPNOTSUPP;
328
+
257329 /* Flag setting protected by i_mutex */
258
- if (is_sxid(amode))
330
+ if (is_sxid(attr->ia_mode))
259331 inode->i_flags &= ~S_NOSEC;
260332 }
261333
....@@ -297,7 +369,7 @@
297369 }
298370 }
299371 if (ia_valid & ATTR_KILL_SGID) {
300
- if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
372
+ if (mode & S_ISGID) {
301373 if (!(ia_valid & ATTR_MODE)) {
302374 ia_valid = attr->ia_valid |= ATTR_MODE;
303375 attr->ia_mode = inode->i_mode;