brintos

brintos / linux-shallow public Read only

0
0
Text · 15.5 KiB · c04d19b Raw
515 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  linux/fs/attr.c4 *5 *  Copyright (C) 1991, 1992  Linus Torvalds6 *  changes by Thomas Schoebel-Theuer7 */8 9#include <linux/export.h>10#include <linux/time.h>11#include <linux/mm.h>12#include <linux/string.h>13#include <linux/sched/signal.h>14#include <linux/capability.h>15#include <linux/fsnotify.h>16#include <linux/fcntl.h>17#include <linux/filelock.h>18#include <linux/security.h>19 20/**21 * setattr_should_drop_sgid - determine whether the setgid bit needs to be22 *                            removed23 * @idmap:	idmap of the mount @inode was found from24 * @inode:	inode to check25 *26 * This function determines whether the setgid bit needs to be removed.27 * We retain backwards compatibility and require setgid bit to be removed28 * unconditionally if S_IXGRP is set. Otherwise we have the exact same29 * requirements as setattr_prepare() and setattr_copy().30 *31 * Return: ATTR_KILL_SGID if setgid bit needs to be removed, 0 otherwise.32 */33int setattr_should_drop_sgid(struct mnt_idmap *idmap,34			     const struct inode *inode)35{36	umode_t mode = inode->i_mode;37 38	if (!(mode & S_ISGID))39		return 0;40	if (mode & S_IXGRP)41		return ATTR_KILL_SGID;42	if (!in_group_or_capable(idmap, inode, i_gid_into_vfsgid(idmap, inode)))43		return ATTR_KILL_SGID;44	return 0;45}46EXPORT_SYMBOL(setattr_should_drop_sgid);47 48/**49 * setattr_should_drop_suidgid - determine whether the set{g,u}id bit needs to50 *                               be dropped51 * @idmap:	idmap of the mount @inode was found from52 * @inode:	inode to check53 *54 * This function determines whether the set{g,u}id bits need to be removed.55 * If the setuid bit needs to be removed ATTR_KILL_SUID is returned. If the56 * setgid bit needs to be removed ATTR_KILL_SGID is returned. If both57 * set{g,u}id bits need to be removed the corresponding mask of both flags is58 * returned.59 *60 * Return: A mask of ATTR_KILL_S{G,U}ID indicating which - if any - setid bits61 * to remove, 0 otherwise.62 */63int setattr_should_drop_suidgid(struct mnt_idmap *idmap,64				struct inode *inode)65{66	umode_t mode = inode->i_mode;67	int kill = 0;68 69	/* suid always must be killed */70	if (unlikely(mode & S_ISUID))71		kill = ATTR_KILL_SUID;72 73	kill |= setattr_should_drop_sgid(idmap, inode);74 75	if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))76		return kill;77 78	return 0;79}80EXPORT_SYMBOL(setattr_should_drop_suidgid);81 82/**83 * chown_ok - verify permissions to chown inode84 * @idmap:	idmap of the mount @inode was found from85 * @inode:	inode to check permissions on86 * @ia_vfsuid:	uid to chown @inode to87 *88 * If the inode has been found through an idmapped mount the idmap of89 * the vfsmount must be passed through @idmap. This function will then90 * take care to map the inode according to @idmap before checking91 * permissions. On non-idmapped mounts or if permission checking is to be92 * performed on the raw inode simply pass @nop_mnt_idmap.93 */94static bool chown_ok(struct mnt_idmap *idmap,95		     const struct inode *inode, vfsuid_t ia_vfsuid)96{97	vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);98	if (vfsuid_eq_kuid(vfsuid, current_fsuid()) &&99	    vfsuid_eq(ia_vfsuid, vfsuid))100		return true;101	if (capable_wrt_inode_uidgid(idmap, inode, CAP_CHOWN))102		return true;103	if (!vfsuid_valid(vfsuid) &&104	    ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))105		return true;106	return false;107}108 109/**110 * chgrp_ok - verify permissions to chgrp inode111 * @idmap:	idmap of the mount @inode was found from112 * @inode:	inode to check permissions on113 * @ia_vfsgid:	gid to chown @inode to114 *115 * If the inode has been found through an idmapped mount the idmap of116 * the vfsmount must be passed through @idmap. This function will then117 * take care to map the inode according to @idmap before checking118 * permissions. On non-idmapped mounts or if permission checking is to be119 * performed on the raw inode simply pass @nop_mnt_idmap.120 */121static bool chgrp_ok(struct mnt_idmap *idmap,122		     const struct inode *inode, vfsgid_t ia_vfsgid)123{124	vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);125	vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);126	if (vfsuid_eq_kuid(vfsuid, current_fsuid())) {127		if (vfsgid_eq(ia_vfsgid, vfsgid))128			return true;129		if (vfsgid_in_group_p(ia_vfsgid))130			return true;131	}132	if (capable_wrt_inode_uidgid(idmap, inode, CAP_CHOWN))133		return true;134	if (!vfsgid_valid(vfsgid) &&135	    ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))136		return true;137	return false;138}139 140/**141 * setattr_prepare - check if attribute changes to a dentry are allowed142 * @idmap:	idmap of the mount the inode was found from143 * @dentry:	dentry to check144 * @attr:	attributes to change145 *146 * Check if we are allowed to change the attributes contained in @attr147 * in the given dentry.  This includes the normal unix access permission148 * checks, as well as checks for rlimits and others. The function also clears149 * SGID bit from mode if user is not allowed to set it. Also file capabilities150 * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.151 *152 * If the inode has been found through an idmapped mount the idmap of153 * the vfsmount must be passed through @idmap. This function will then154 * take care to map the inode according to @idmap before checking155 * permissions. On non-idmapped mounts or if permission checking is to be156 * performed on the raw inode simply pass @nop_mnt_idmap.157 *158 * Should be called as the first thing in ->setattr implementations,159 * possibly after taking additional locks.160 */161int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry,162		    struct iattr *attr)163{164	struct inode *inode = d_inode(dentry);165	unsigned int ia_valid = attr->ia_valid;166 167	/*168	 * First check size constraints.  These can't be overriden using169	 * ATTR_FORCE.170	 */171	if (ia_valid & ATTR_SIZE) {172		int error = inode_newsize_ok(inode, attr->ia_size);173		if (error)174			return error;175	}176 177	/* If force is set do it anyway. */178	if (ia_valid & ATTR_FORCE)179		goto kill_priv;180 181	/* Make sure a caller can chown. */182	if ((ia_valid & ATTR_UID) &&183	    !chown_ok(idmap, inode, attr->ia_vfsuid))184		return -EPERM;185 186	/* Make sure caller can chgrp. */187	if ((ia_valid & ATTR_GID) &&188	    !chgrp_ok(idmap, inode, attr->ia_vfsgid))189		return -EPERM;190 191	/* Make sure a caller can chmod. */192	if (ia_valid & ATTR_MODE) {193		vfsgid_t vfsgid;194 195		if (!inode_owner_or_capable(idmap, inode))196			return -EPERM;197 198		if (ia_valid & ATTR_GID)199			vfsgid = attr->ia_vfsgid;200		else201			vfsgid = i_gid_into_vfsgid(idmap, inode);202 203		/* Also check the setgid bit! */204		if (!in_group_or_capable(idmap, inode, vfsgid))205			attr->ia_mode &= ~S_ISGID;206	}207 208	/* Check for setting the inode time. */209	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {210		if (!inode_owner_or_capable(idmap, inode))211			return -EPERM;212	}213 214kill_priv:215	/* User has permission for the change */216	if (ia_valid & ATTR_KILL_PRIV) {217		int error;218 219		error = security_inode_killpriv(idmap, dentry);220		if (error)221			return error;222	}223 224	return 0;225}226EXPORT_SYMBOL(setattr_prepare);227 228/**229 * inode_newsize_ok - may this inode be truncated to a given size230 * @inode:	the inode to be truncated231 * @offset:	the new size to assign to the inode232 *233 * inode_newsize_ok must be called with i_mutex held.234 *235 * inode_newsize_ok will check filesystem limits and ulimits to check that the236 * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ237 * when necessary. Caller must not proceed with inode size change if failure is238 * returned. @inode must be a file (not directory), with appropriate239 * permissions to allow truncate (inode_newsize_ok does NOT check these240 * conditions).241 *242 * Return: 0 on success, -ve errno on failure243 */244int inode_newsize_ok(const struct inode *inode, loff_t offset)245{246	if (offset < 0)247		return -EINVAL;248	if (inode->i_size < offset) {249		unsigned long limit;250 251		limit = rlimit(RLIMIT_FSIZE);252		if (limit != RLIM_INFINITY && offset > limit)253			goto out_sig;254		if (offset > inode->i_sb->s_maxbytes)255			goto out_big;256	} else {257		/*258		 * truncation of in-use swapfiles is disallowed - it would259		 * cause subsequent swapout to scribble on the now-freed260		 * blocks.261		 */262		if (IS_SWAPFILE(inode))263			return -ETXTBSY;264	}265 266	return 0;267out_sig:268	send_sig(SIGXFSZ, current, 0);269out_big:270	return -EFBIG;271}272EXPORT_SYMBOL(inode_newsize_ok);273 274/**275 * setattr_copy - copy simple metadata updates into the generic inode276 * @idmap:	idmap of the mount the inode was found from277 * @inode:	the inode to be updated278 * @attr:	the new attributes279 *280 * setattr_copy must be called with i_mutex held.281 *282 * setattr_copy updates the inode's metadata with that specified283 * in attr on idmapped mounts. Necessary permission checks to determine284 * whether or not the S_ISGID property needs to be removed are performed with285 * the correct idmapped mount permission helpers.286 * Noticeably missing is inode size update, which is more complex287 * as it requires pagecache updates.288 *289 * If the inode has been found through an idmapped mount the idmap of290 * the vfsmount must be passed through @idmap. This function will then291 * take care to map the inode according to @idmap before checking292 * permissions. On non-idmapped mounts or if permission checking is to be293 * performed on the raw inode simply pass @nop_mnt_idmap.294 *295 * The inode is not marked as dirty after this operation. The rationale is296 * that for "simple" filesystems, the struct inode is the inode storage.297 * The caller is free to mark the inode dirty afterwards if needed.298 */299void setattr_copy(struct mnt_idmap *idmap, struct inode *inode,300		  const struct iattr *attr)301{302	unsigned int ia_valid = attr->ia_valid;303 304	i_uid_update(idmap, attr, inode);305	i_gid_update(idmap, attr, inode);306	if (ia_valid & ATTR_ATIME)307		inode_set_atime_to_ts(inode, attr->ia_atime);308	if (ia_valid & ATTR_MTIME)309		inode_set_mtime_to_ts(inode, attr->ia_mtime);310	if (ia_valid & ATTR_CTIME)311		inode_set_ctime_to_ts(inode, attr->ia_ctime);312	if (ia_valid & ATTR_MODE) {313		umode_t mode = attr->ia_mode;314		if (!in_group_or_capable(idmap, inode,315					 i_gid_into_vfsgid(idmap, inode)))316			mode &= ~S_ISGID;317		inode->i_mode = mode;318	}319}320EXPORT_SYMBOL(setattr_copy);321 322int may_setattr(struct mnt_idmap *idmap, struct inode *inode,323		unsigned int ia_valid)324{325	int error;326 327	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {328		if (IS_IMMUTABLE(inode) || IS_APPEND(inode))329			return -EPERM;330	}331 332	/*333	 * If utimes(2) and friends are called with times == NULL (or both334	 * times are UTIME_NOW), then we need to check for write permission335	 */336	if (ia_valid & ATTR_TOUCH) {337		if (IS_IMMUTABLE(inode))338			return -EPERM;339 340		if (!inode_owner_or_capable(idmap, inode)) {341			error = inode_permission(idmap, inode, MAY_WRITE);342			if (error)343				return error;344		}345	}346	return 0;347}348EXPORT_SYMBOL(may_setattr);349 350/**351 * notify_change - modify attributes of a filesystem object352 * @idmap:	idmap of the mount the inode was found from353 * @dentry:	object affected354 * @attr:	new attributes355 * @delegated_inode: returns inode, if the inode is delegated356 *357 * The caller must hold the i_mutex on the affected object.358 *359 * If notify_change discovers a delegation in need of breaking,360 * it will return -EWOULDBLOCK and return a reference to the inode in361 * delegated_inode.  The caller should then break the delegation and362 * retry.  Because breaking a delegation may take a long time, the363 * caller should drop the i_mutex before doing so.364 *365 * Alternatively, a caller may pass NULL for delegated_inode.  This may366 * be appropriate for callers that expect the underlying filesystem not367 * to be NFS exported.  Also, passing NULL is fine for callers holding368 * the file open for write, as there can be no conflicting delegation in369 * that case.370 *371 * If the inode has been found through an idmapped mount the idmap of372 * the vfsmount must be passed through @idmap. This function will then373 * take care to map the inode according to @idmap before checking374 * permissions. On non-idmapped mounts or if permission checking is to be375 * performed on the raw inode simply pass @nop_mnt_idmap.376 */377int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,378		  struct iattr *attr, struct inode **delegated_inode)379{380	struct inode *inode = dentry->d_inode;381	umode_t mode = inode->i_mode;382	int error;383	struct timespec64 now;384	unsigned int ia_valid = attr->ia_valid;385 386	WARN_ON_ONCE(!inode_is_locked(inode));387 388	error = may_setattr(idmap, inode, ia_valid);389	if (error)390		return error;391 392	if ((ia_valid & ATTR_MODE)) {393		/*394		 * Don't allow changing the mode of symlinks:395		 *396		 * (1) The vfs doesn't take the mode of symlinks into account397		 *     during permission checking.398		 * (2) This has never worked correctly. Most major filesystems399		 *     did return EOPNOTSUPP due to interactions with POSIX ACLs400		 *     but did still updated the mode of the symlink.401		 *     This inconsistency led system call wrapper providers such402		 *     as libc to block changing the mode of symlinks with403		 *     EOPNOTSUPP already.404		 * (3) To even do this in the first place one would have to use405		 *     specific file descriptors and quite some effort.406		 */407		if (S_ISLNK(inode->i_mode))408			return -EOPNOTSUPP;409 410		/* Flag setting protected by i_mutex */411		if (is_sxid(attr->ia_mode))412			inode->i_flags &= ~S_NOSEC;413	}414 415	now = current_time(inode);416 417	attr->ia_ctime = now;418	if (!(ia_valid & ATTR_ATIME_SET))419		attr->ia_atime = now;420	else421		attr->ia_atime = timestamp_truncate(attr->ia_atime, inode);422	if (!(ia_valid & ATTR_MTIME_SET))423		attr->ia_mtime = now;424	else425		attr->ia_mtime = timestamp_truncate(attr->ia_mtime, inode);426 427	if (ia_valid & ATTR_KILL_PRIV) {428		error = security_inode_need_killpriv(dentry);429		if (error < 0)430			return error;431		if (error == 0)432			ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;433	}434 435	/*436	 * We now pass ATTR_KILL_S*ID to the lower level setattr function so437	 * that the function has the ability to reinterpret a mode change438	 * that's due to these bits. This adds an implicit restriction that439	 * no function will ever call notify_change with both ATTR_MODE and440	 * ATTR_KILL_S*ID set.441	 */442	if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) &&443	    (ia_valid & ATTR_MODE))444		BUG();445 446	if (ia_valid & ATTR_KILL_SUID) {447		if (mode & S_ISUID) {448			ia_valid = attr->ia_valid |= ATTR_MODE;449			attr->ia_mode = (inode->i_mode & ~S_ISUID);450		}451	}452	if (ia_valid & ATTR_KILL_SGID) {453		if (mode & S_ISGID) {454			if (!(ia_valid & ATTR_MODE)) {455				ia_valid = attr->ia_valid |= ATTR_MODE;456				attr->ia_mode = inode->i_mode;457			}458			attr->ia_mode &= ~S_ISGID;459		}460	}461	if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))462		return 0;463 464	/*465	 * Verify that uid/gid changes are valid in the target466	 * namespace of the superblock.467	 */468	if (ia_valid & ATTR_UID &&469	    !vfsuid_has_fsmapping(idmap, inode->i_sb->s_user_ns,470				  attr->ia_vfsuid))471		return -EOVERFLOW;472	if (ia_valid & ATTR_GID &&473	    !vfsgid_has_fsmapping(idmap, inode->i_sb->s_user_ns,474				  attr->ia_vfsgid))475		return -EOVERFLOW;476 477	/* Don't allow modifications of files with invalid uids or478	 * gids unless those uids & gids are being made valid.479	 */480	if (!(ia_valid & ATTR_UID) &&481	    !vfsuid_valid(i_uid_into_vfsuid(idmap, inode)))482		return -EOVERFLOW;483	if (!(ia_valid & ATTR_GID) &&484	    !vfsgid_valid(i_gid_into_vfsgid(idmap, inode)))485		return -EOVERFLOW;486 487	error = security_inode_setattr(idmap, dentry, attr);488	if (error)489		return error;490 491	/*492	 * If ATTR_DELEG is set, then these attributes are being set on493	 * behalf of the holder of a write delegation. We want to avoid494	 * breaking the delegation in this case.495	 */496	if (!(ia_valid & ATTR_DELEG)) {497		error = try_break_deleg(inode, delegated_inode);498		if (error)499			return error;500	}501 502	if (inode->i_op->setattr)503		error = inode->i_op->setattr(idmap, dentry, attr);504	else505		error = simple_setattr(idmap, dentry, attr);506 507	if (!error) {508		fsnotify_change(dentry, ia_valid);509		security_inode_post_setattr(idmap, dentry, ia_valid);510	}511 512	return error;513}514EXPORT_SYMBOL(notify_change);515