.. | .. |
---|
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 | |
---|
.. | .. |
---|
114 | 172 | |
---|
115 | 173 | return 0; |
---|
116 | 174 | } |
---|
117 | | -EXPORT_SYMBOL(setattr_prepare); |
---|
| 175 | +EXPORT_SYMBOL_NS(setattr_prepare, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
118 | 176 | |
---|
119 | 177 | /** |
---|
120 | 178 | * inode_newsize_ok - may this inode be truncated to a given size |
---|
.. | .. |
---|
134 | 192 | */ |
---|
135 | 193 | int inode_newsize_ok(const struct inode *inode, loff_t offset) |
---|
136 | 194 | { |
---|
| 195 | + if (offset < 0) |
---|
| 196 | + return -EINVAL; |
---|
137 | 197 | if (inode->i_size < offset) { |
---|
138 | 198 | unsigned long limit; |
---|
139 | 199 | |
---|
.. | .. |
---|
158 | 218 | out_big: |
---|
159 | 219 | return -EFBIG; |
---|
160 | 220 | } |
---|
161 | | -EXPORT_SYMBOL(inode_newsize_ok); |
---|
| 221 | +EXPORT_SYMBOL_NS(inode_newsize_ok, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
162 | 222 | |
---|
163 | 223 | /** |
---|
164 | 224 | * setattr_copy - copy simple metadata updates into the generic inode |
---|
.. | .. |
---|
184 | 244 | if (ia_valid & ATTR_GID) |
---|
185 | 245 | inode->i_gid = attr->ia_gid; |
---|
186 | 246 | if (ia_valid & ATTR_ATIME) |
---|
187 | | - inode->i_atime = timespec64_trunc(attr->ia_atime, |
---|
188 | | - inode->i_sb->s_time_gran); |
---|
| 247 | + inode->i_atime = attr->ia_atime; |
---|
189 | 248 | if (ia_valid & ATTR_MTIME) |
---|
190 | | - inode->i_mtime = timespec64_trunc(attr->ia_mtime, |
---|
191 | | - inode->i_sb->s_time_gran); |
---|
| 249 | + inode->i_mtime = attr->ia_mtime; |
---|
192 | 250 | if (ia_valid & ATTR_CTIME) |
---|
193 | | - inode->i_ctime = timespec64_trunc(attr->ia_ctime, |
---|
194 | | - inode->i_sb->s_time_gran); |
---|
| 251 | + inode->i_ctime = attr->ia_ctime; |
---|
195 | 252 | if (ia_valid & ATTR_MODE) { |
---|
196 | 253 | umode_t mode = attr->ia_mode; |
---|
197 | | - |
---|
198 | | - if (!in_group_p(inode->i_gid) && |
---|
199 | | - !capable_wrt_inode_uidgid(inode, CAP_FSETID)) |
---|
| 254 | + if (!in_group_or_capable(inode, inode->i_gid)) |
---|
200 | 255 | mode &= ~S_ISGID; |
---|
201 | 256 | inode->i_mode = mode; |
---|
202 | 257 | } |
---|
.. | .. |
---|
223 | 278 | * the file open for write, as there can be no conflicting delegation in |
---|
224 | 279 | * that case. |
---|
225 | 280 | */ |
---|
226 | | -int notify_change2(struct vfsmount *mnt, struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode) |
---|
| 281 | +int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode) |
---|
227 | 282 | { |
---|
228 | 283 | struct inode *inode = dentry->d_inode; |
---|
229 | 284 | umode_t mode = inode->i_mode; |
---|
.. | .. |
---|
247 | 302 | return -EPERM; |
---|
248 | 303 | |
---|
249 | 304 | if (!inode_owner_or_capable(inode)) { |
---|
250 | | - error = inode_permission2(mnt, inode, MAY_WRITE); |
---|
| 305 | + error = inode_permission(inode, MAY_WRITE); |
---|
251 | 306 | if (error) |
---|
252 | 307 | return error; |
---|
253 | 308 | } |
---|
254 | 309 | } |
---|
255 | 310 | |
---|
256 | 311 | if ((ia_valid & ATTR_MODE)) { |
---|
257 | | - 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 | + |
---|
258 | 329 | /* Flag setting protected by i_mutex */ |
---|
259 | | - if (is_sxid(amode)) |
---|
| 330 | + if (is_sxid(attr->ia_mode)) |
---|
260 | 331 | inode->i_flags &= ~S_NOSEC; |
---|
261 | 332 | } |
---|
262 | 333 | |
---|
.. | .. |
---|
265 | 336 | attr->ia_ctime = now; |
---|
266 | 337 | if (!(ia_valid & ATTR_ATIME_SET)) |
---|
267 | 338 | attr->ia_atime = now; |
---|
| 339 | + else |
---|
| 340 | + attr->ia_atime = timestamp_truncate(attr->ia_atime, inode); |
---|
268 | 341 | if (!(ia_valid & ATTR_MTIME_SET)) |
---|
269 | 342 | attr->ia_mtime = now; |
---|
| 343 | + else |
---|
| 344 | + attr->ia_mtime = timestamp_truncate(attr->ia_mtime, inode); |
---|
| 345 | + |
---|
270 | 346 | if (ia_valid & ATTR_KILL_PRIV) { |
---|
271 | 347 | error = security_inode_need_killpriv(dentry); |
---|
272 | 348 | if (error < 0) |
---|
.. | .. |
---|
293 | 369 | } |
---|
294 | 370 | } |
---|
295 | 371 | if (ia_valid & ATTR_KILL_SGID) { |
---|
296 | | - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
---|
| 372 | + if (mode & S_ISGID) { |
---|
297 | 373 | if (!(ia_valid & ATTR_MODE)) { |
---|
298 | 374 | ia_valid = attr->ia_valid |= ATTR_MODE; |
---|
299 | 375 | attr->ia_mode = inode->i_mode; |
---|
.. | .. |
---|
330 | 406 | if (error) |
---|
331 | 407 | return error; |
---|
332 | 408 | |
---|
333 | | - if (mnt && inode->i_op->setattr2) |
---|
334 | | - error = inode->i_op->setattr2(mnt, dentry, attr); |
---|
335 | | - else if (inode->i_op->setattr) |
---|
| 409 | + if (inode->i_op->setattr) |
---|
336 | 410 | error = inode->i_op->setattr(dentry, attr); |
---|
337 | 411 | else |
---|
338 | 412 | error = simple_setattr(dentry, attr); |
---|
.. | .. |
---|
345 | 419 | |
---|
346 | 420 | return error; |
---|
347 | 421 | } |
---|
348 | | -EXPORT_SYMBOL(notify_change2); |
---|
349 | | - |
---|
350 | | -int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode) |
---|
351 | | -{ |
---|
352 | | - return notify_change2(NULL, dentry, attr, delegated_inode); |
---|
353 | | -} |
---|
354 | | -EXPORT_SYMBOL(notify_change); |
---|
| 422 | +EXPORT_SYMBOL_NS(notify_change, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|