1761 lines · 45.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/*  File: fs/xattr.c   Extended attribute handling.   Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>  Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>  Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> */#include <linux/fs.h>#include <linux/filelock.h>#include <linux/slab.h>#include <linux/file.h>#include <linux/xattr.h>#include <linux/mount.h>#include <linux/namei.h>#include <linux/security.h>#include <linux/syscalls.h>#include <linux/export.h>#include <linux/fsnotify.h>#include <linux/audit.h>#include <linux/vmalloc.h>#include <linux/posix_acl_xattr.h>#include <linux/rhashtable.h> #include <linux/uaccess.h> #include "internal.h" struct sx_key {	const struct list_head *parent;	const char *name;}; static const char *strcmp_prefix(const char *a, const char *a_prefix){	while (*a_prefix && *a == *a_prefix) {		a++;		a_prefix++;	}	return *a_prefix ? NULL : a;} /* * In order to implement different sets of xattr operations for each xattr * prefix, a filesystem should create a null-terminated array of struct * xattr_handler (one for each prefix) and hang a pointer to it off of the * s_xattr field of the superblock. */#define for_each_xattr_handler(handlers, handler)		\	if (handlers)						\		for ((handler) = *(handlers)++;			\			(handler) != NULL;			\			(handler) = *(handlers)++) /* * Find the xattr_handler with the matching prefix. */static const struct xattr_handler *xattr_resolve_name(struct inode *inode, const char **name){	const struct xattr_handler * const *handlers = inode->i_sb->s_xattr;	const struct xattr_handler *handler; 	if (!(inode->i_opflags & IOP_XATTR)) {		if (unlikely(is_bad_inode(inode)))			return ERR_PTR(-EIO);		return ERR_PTR(-EOPNOTSUPP);	}	for_each_xattr_handler(handlers, handler) {		const char *n; 		n = strcmp_prefix(*name, xattr_prefix(handler));		if (n) {			if (!handler->prefix ^ !*n) {				if (*n)					continue;				return ERR_PTR(-EINVAL);			}			*name = n;			return handler;		}	}	return ERR_PTR(-EOPNOTSUPP);} /** * may_write_xattr - check whether inode allows writing xattr * @idmap: idmap of the mount the inode was found from * @inode: the inode on which to set an xattr * * Check whether the inode allows writing xattrs. Specifically, we can never * set or remove an extended attribute on a read-only filesystem  or on an * immutable / append-only inode. * * We also need to ensure that the inode has a mapping in the mount to * not risk writing back invalid i_{g,u}id values. * * Return: On success zero is returned. On error a negative errno is returned. */int may_write_xattr(struct mnt_idmap *idmap, struct inode *inode){	if (IS_IMMUTABLE(inode))		return -EPERM;	if (IS_APPEND(inode))		return -EPERM;	if (HAS_UNMAPPED_ID(idmap, inode))		return -EPERM;	return 0;} static inline int xattr_permission_error(int mask){	if (mask & MAY_WRITE)		return -EPERM;	return -ENODATA;} /* * Check permissions for extended attribute access.  This is a bit complicated * because different namespaces have very different rules. */static intxattr_permission(struct mnt_idmap *idmap, struct inode *inode,		 const char *name, int mask){	if (mask & MAY_WRITE) {		int ret; 		ret = may_write_xattr(idmap, inode);		if (ret)			return ret;	} 	/*	 * No restriction for security.* and system.* from the VFS.  Decision	 * on these is left to the underlying filesystem / security module.	 */	if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||	    !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))		return 0; 	/*	 * The trusted.* namespace can only be accessed by privileged users.	 */	if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {		if (!capable(CAP_SYS_ADMIN))			return xattr_permission_error(mask);		return 0;	} 	/*	 * In the user.* namespace, only regular files and directories can have	 * extended attributes. For sticky directories, only the owner and	 * privileged users can write attributes.	 */	if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {		switch (inode->i_mode & S_IFMT) {		case S_IFREG:			break;		case S_IFDIR:			if (!(inode->i_mode & S_ISVTX))				break;			if (!(mask & MAY_WRITE))				break;			if (inode_owner_or_capable(idmap, inode))				break;			return -EPERM;		case S_IFSOCK:			break;		default:			return xattr_permission_error(mask);		}	} 	return inode_permission(idmap, inode, mask);} /* * Look for any handler that deals with the specified namespace. */intxattr_supports_user_prefix(struct inode *inode){	const struct xattr_handler * const *handlers = inode->i_sb->s_xattr;	const struct xattr_handler *handler; 	if (!(inode->i_opflags & IOP_XATTR)) {		if (unlikely(is_bad_inode(inode)))			return -EIO;		return -EOPNOTSUPP;	} 	for_each_xattr_handler(handlers, handler) {		if (!strncmp(xattr_prefix(handler), XATTR_USER_PREFIX,			     XATTR_USER_PREFIX_LEN))			return 0;	} 	return -EOPNOTSUPP;}EXPORT_SYMBOL(xattr_supports_user_prefix); int__vfs_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,	       struct inode *inode, const char *name, const void *value,	       size_t size, int flags){	const struct xattr_handler *handler; 	if (is_posix_acl_xattr(name))		return -EOPNOTSUPP; 	handler = xattr_resolve_name(inode, &name);	if (IS_ERR(handler))		return PTR_ERR(handler);	if (!handler->set)		return -EOPNOTSUPP;	if (size == 0)		value = "";  /* empty EA, do not remove */	return handler->set(handler, idmap, dentry, inode, name, value,			    size, flags);}EXPORT_SYMBOL(__vfs_setxattr); /** *  __vfs_setxattr_noperm - perform setxattr operation without performing *  permission checks. * *  @idmap: idmap of the mount the inode was found from *  @dentry: object to perform setxattr on *  @name: xattr name to set *  @value: value to set @name to *  @size: size of @value *  @flags: flags to pass into filesystem operations * *  returns the result of the internal setxattr or setsecurity operations. * *  This function requires the caller to lock the inode's i_rwsem before it *  is executed. It also assumes that the caller will make the appropriate *  permission checks. */int __vfs_setxattr_noperm(struct mnt_idmap *idmap,			  struct dentry *dentry, const char *name,			  const void *value, size_t size, int flags){	struct inode *inode = dentry->d_inode;	int error = -EAGAIN;	int issec = !strncmp(name, XATTR_SECURITY_PREFIX,				   XATTR_SECURITY_PREFIX_LEN); 	if (issec)		inode->i_flags &= ~S_NOSEC;	if (inode->i_opflags & IOP_XATTR) {		error = __vfs_setxattr(idmap, dentry, inode, name, value,				       size, flags);		if (!error) {			fsnotify_xattr(dentry);			security_inode_post_setxattr(dentry, name, value,						     size, flags);		}	} else {		if (unlikely(is_bad_inode(inode)))			return -EIO;	}	if (error == -EAGAIN) {		error = -EOPNOTSUPP; 		if (issec) {			const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; 			error = security_inode_setsecurity(inode, suffix, value,							   size, flags);			if (!error)				fsnotify_xattr(dentry);		}	} 	return error;} /** * __vfs_setxattr_locked - set an extended attribute while holding the inode * lock * *  @idmap: idmap of the mount of the target inode *  @dentry: object to perform setxattr on *  @name: xattr name to set *  @value: value to set @name to *  @size: size of @value *  @flags: flags to pass into filesystem operations *  @delegated_inode: on return, will contain an inode pointer that *  a delegation was broken on, NULL if none. */int__vfs_setxattr_locked(struct mnt_idmap *idmap, struct dentry *dentry,		      const char *name, const void *value, size_t size,		      int flags, struct delegated_inode *delegated_inode){	struct inode *inode = dentry->d_inode;	int error; 	error = xattr_permission(idmap, inode, name, MAY_WRITE);	if (error)		return error; 	error = security_inode_setxattr(idmap, dentry, name, value, size,					flags);	if (error)		goto out; 	error = try_break_deleg(inode, 0, delegated_inode);	if (error)		goto out; 	error = __vfs_setxattr_noperm(idmap, dentry, name, value,				      size, flags); out:	return error;}EXPORT_SYMBOL_GPL(__vfs_setxattr_locked); intvfs_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,	     const char *name, const void *value, size_t size, int flags){	struct inode *inode = dentry->d_inode;	struct delegated_inode delegated_inode = { };	const void  *orig_value = value;	int error; 	if (size && strcmp(name, XATTR_NAME_CAPS) == 0) {		error = cap_convert_nscap(idmap, dentry, &value, size);		if (error < 0)			return error;		size = error;	} retry_deleg:	inode_lock(inode);	error = __vfs_setxattr_locked(idmap, dentry, name, value, size,				      flags, &delegated_inode);	inode_unlock(inode); 	if (is_delegated(&delegated_inode)) {		error = break_deleg_wait(&delegated_inode);		if (!error)			goto retry_deleg;	}	if (value != orig_value)		kfree(value); 	return error;}EXPORT_SYMBOL_GPL(vfs_setxattr); static ssize_txattr_getsecurity(struct mnt_idmap *idmap, struct inode *inode,		  const char *name, void *value, size_t size){	void *buffer = NULL;	ssize_t len; 	if (!value || !size) {		len = security_inode_getsecurity(idmap, inode, name,						 &buffer, false);		goto out_noalloc;	} 	len = security_inode_getsecurity(idmap, inode, name, &buffer,					 true);	if (len < 0)		return len;	if (size < len) {		len = -ERANGE;		goto out;	}	memcpy(value, buffer, len);out:	kfree(buffer);out_noalloc:	return len;} /* * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr * * Allocate memory, if not already allocated, or re-allocate correct size, * before retrieving the extended attribute.  The xattr value buffer should * always be freed by the caller, even on error. * * Returns the result of alloc, if failed, or the getxattr operation. */intvfs_getxattr_alloc(struct mnt_idmap *idmap, struct dentry *dentry,		   const char *name, char **xattr_value, size_t xattr_size,		   gfp_t flags){	const struct xattr_handler *handler;	struct inode *inode = dentry->d_inode;	char *value = *xattr_value;	int error; 	error = xattr_permission(idmap, inode, name, MAY_READ);	if (error)		return error; 	handler = xattr_resolve_name(inode, &name);	if (IS_ERR(handler))		return PTR_ERR(handler);	if (!handler->get)		return -EOPNOTSUPP;	error = handler->get(handler, dentry, inode, name, NULL, 0);	if (error < 0)		return error; 	if (!value || (error > xattr_size)) {		value = krealloc(*xattr_value, error + 1, flags);		if (!value)			return -ENOMEM;		memset(value, 0, error + 1);	} 	error = handler->get(handler, dentry, inode, name, value, error);	*xattr_value = value;	return error;} ssize_t__vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,	       void *value, size_t size){	const struct xattr_handler *handler; 	if (is_posix_acl_xattr(name))		return -EOPNOTSUPP; 	handler = xattr_resolve_name(inode, &name);	if (IS_ERR(handler))		return PTR_ERR(handler);	if (!handler->get)		return -EOPNOTSUPP;	return handler->get(handler, dentry, inode, name, value, size);}EXPORT_SYMBOL(__vfs_getxattr); ssize_tvfs_getxattr(struct mnt_idmap *idmap, struct dentry *dentry,	     const char *name, void *value, size_t size){	struct inode *inode = dentry->d_inode;	int error; 	error = xattr_permission(idmap, inode, name, MAY_READ);	if (error)		return error; 	error = security_inode_getxattr(dentry, name);	if (error)		return error; 	if (!strncmp(name, XATTR_SECURITY_PREFIX,				XATTR_SECURITY_PREFIX_LEN)) {		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;		int ret = xattr_getsecurity(idmap, inode, suffix, value,					    size);		/*		 * Only overwrite the return value if a security module		 * is actually active.		 */		if (ret == -EOPNOTSUPP)			goto nolsm;		return ret;	}nolsm:	return __vfs_getxattr(dentry, inode, name, value, size);}EXPORT_SYMBOL_GPL(vfs_getxattr); /** * vfs_listxattr - retrieve \0 separated list of xattr names * @dentry: the dentry from whose inode the xattr names are retrieved * @list: buffer to store xattr names into * @size: size of the buffer * * This function returns the names of all xattrs associated with the * inode of @dentry. * * Note, for legacy reasons the vfs_listxattr() function lists POSIX * ACLs as well. Since POSIX ACLs are decoupled from IOP_XATTR the * vfs_listxattr() function doesn't check for this flag since a * filesystem could implement POSIX ACLs without implementing any other * xattrs. * * However, since all codepaths that remove IOP_XATTR also assign of * inode operations that either don't implement or implement a stub * ->listxattr() operation.

Lines 1–500 of 1761.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t