| .. | .. |
|---|
| 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); |
|---|