.. | .. |
---|
18 | 18 | #include <linux/evm.h> |
---|
19 | 19 | #include <linux/ima.h> |
---|
20 | 20 | |
---|
| 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 | + |
---|
21 | 80 | static bool chown_ok(const struct inode *inode, kuid_t uid) |
---|
22 | 81 | { |
---|
23 | 82 | if (uid_eq(current_fsuid(), inode->i_uid) && |
---|
.. | .. |
---|
90 | 149 | if (!inode_owner_or_capable(inode)) |
---|
91 | 150 | return -EPERM; |
---|
92 | 151 | /* 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)) |
---|
96 | 154 | attr->ia_mode &= ~S_ISGID; |
---|
97 | 155 | } |
---|
98 | 156 | |
---|
.. | .. |
---|
193 | 251 | inode->i_ctime = attr->ia_ctime; |
---|
194 | 252 | if (ia_valid & ATTR_MODE) { |
---|
195 | 253 | 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)) |
---|
199 | 255 | mode &= ~S_ISGID; |
---|
200 | 256 | inode->i_mode = mode; |
---|
201 | 257 | } |
---|
.. | .. |
---|
253 | 309 | } |
---|
254 | 310 | |
---|
255 | 311 | 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 | + |
---|
257 | 329 | /* Flag setting protected by i_mutex */ |
---|
258 | | - if (is_sxid(amode)) |
---|
| 330 | + if (is_sxid(attr->ia_mode)) |
---|
259 | 331 | inode->i_flags &= ~S_NOSEC; |
---|
260 | 332 | } |
---|
261 | 333 | |
---|
.. | .. |
---|
297 | 369 | } |
---|
298 | 370 | } |
---|
299 | 371 | if (ia_valid & ATTR_KILL_SGID) { |
---|
300 | | - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
---|
| 372 | + if (mode & S_ISGID) { |
---|
301 | 373 | if (!(ia_valid & ATTR_MODE)) { |
---|
302 | 374 | ia_valid = attr->ia_valid |= ATTR_MODE; |
---|
303 | 375 | attr->ia_mode = inode->i_mode; |
---|