162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci  File: fs/xattr.c
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci  Extended attribute handling.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
862306a36Sopenharmony_ci  Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
962306a36Sopenharmony_ci  Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <linux/fs.h>
1262306a36Sopenharmony_ci#include <linux/filelock.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/file.h>
1562306a36Sopenharmony_ci#include <linux/xattr.h>
1662306a36Sopenharmony_ci#include <linux/mount.h>
1762306a36Sopenharmony_ci#include <linux/namei.h>
1862306a36Sopenharmony_ci#include <linux/security.h>
1962306a36Sopenharmony_ci#include <linux/evm.h>
2062306a36Sopenharmony_ci#include <linux/syscalls.h>
2162306a36Sopenharmony_ci#include <linux/export.h>
2262306a36Sopenharmony_ci#include <linux/fsnotify.h>
2362306a36Sopenharmony_ci#include <linux/audit.h>
2462306a36Sopenharmony_ci#include <linux/vmalloc.h>
2562306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <linux/uaccess.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "internal.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic const char *
3262306a36Sopenharmony_cistrcmp_prefix(const char *a, const char *a_prefix)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	while (*a_prefix && *a == *a_prefix) {
3562306a36Sopenharmony_ci		a++;
3662306a36Sopenharmony_ci		a_prefix++;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci	return *a_prefix ? NULL : a;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * In order to implement different sets of xattr operations for each xattr
4362306a36Sopenharmony_ci * prefix, a filesystem should create a null-terminated array of struct
4462306a36Sopenharmony_ci * xattr_handler (one for each prefix) and hang a pointer to it off of the
4562306a36Sopenharmony_ci * s_xattr field of the superblock.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci#define for_each_xattr_handler(handlers, handler)		\
4862306a36Sopenharmony_ci	if (handlers)						\
4962306a36Sopenharmony_ci		for ((handler) = *(handlers)++;			\
5062306a36Sopenharmony_ci			(handler) != NULL;			\
5162306a36Sopenharmony_ci			(handler) = *(handlers)++)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/*
5462306a36Sopenharmony_ci * Find the xattr_handler with the matching prefix.
5562306a36Sopenharmony_ci */
5662306a36Sopenharmony_cistatic const struct xattr_handler *
5762306a36Sopenharmony_cixattr_resolve_name(struct inode *inode, const char **name)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	const struct xattr_handler **handlers = inode->i_sb->s_xattr;
6062306a36Sopenharmony_ci	const struct xattr_handler *handler;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (!(inode->i_opflags & IOP_XATTR)) {
6362306a36Sopenharmony_ci		if (unlikely(is_bad_inode(inode)))
6462306a36Sopenharmony_ci			return ERR_PTR(-EIO);
6562306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci	for_each_xattr_handler(handlers, handler) {
6862306a36Sopenharmony_ci		const char *n;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci		n = strcmp_prefix(*name, xattr_prefix(handler));
7162306a36Sopenharmony_ci		if (n) {
7262306a36Sopenharmony_ci			if (!handler->prefix ^ !*n) {
7362306a36Sopenharmony_ci				if (*n)
7462306a36Sopenharmony_ci					continue;
7562306a36Sopenharmony_ci				return ERR_PTR(-EINVAL);
7662306a36Sopenharmony_ci			}
7762306a36Sopenharmony_ci			*name = n;
7862306a36Sopenharmony_ci			return handler;
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci	return ERR_PTR(-EOPNOTSUPP);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/**
8562306a36Sopenharmony_ci * may_write_xattr - check whether inode allows writing xattr
8662306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from
8762306a36Sopenharmony_ci * @inode: the inode on which to set an xattr
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * Check whether the inode allows writing xattrs. Specifically, we can never
9062306a36Sopenharmony_ci * set or remove an extended attribute on a read-only filesystem  or on an
9162306a36Sopenharmony_ci * immutable / append-only inode.
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * We also need to ensure that the inode has a mapping in the mount to
9462306a36Sopenharmony_ci * not risk writing back invalid i_{g,u}id values.
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * Return: On success zero is returned. On error a negative errno is returned.
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_ciint may_write_xattr(struct mnt_idmap *idmap, struct inode *inode)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	if (IS_IMMUTABLE(inode))
10162306a36Sopenharmony_ci		return -EPERM;
10262306a36Sopenharmony_ci	if (IS_APPEND(inode))
10362306a36Sopenharmony_ci		return -EPERM;
10462306a36Sopenharmony_ci	if (HAS_UNMAPPED_ID(idmap, inode))
10562306a36Sopenharmony_ci		return -EPERM;
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/*
11062306a36Sopenharmony_ci * Check permissions for extended attribute access.  This is a bit complicated
11162306a36Sopenharmony_ci * because different namespaces have very different rules.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistatic int
11462306a36Sopenharmony_cixattr_permission(struct mnt_idmap *idmap, struct inode *inode,
11562306a36Sopenharmony_ci		 const char *name, int mask)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	if (mask & MAY_WRITE) {
11862306a36Sopenharmony_ci		int ret;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		ret = may_write_xattr(idmap, inode);
12162306a36Sopenharmony_ci		if (ret)
12262306a36Sopenharmony_ci			return ret;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/*
12662306a36Sopenharmony_ci	 * No restriction for security.* and system.* from the VFS.  Decision
12762306a36Sopenharmony_ci	 * on these is left to the underlying filesystem / security module.
12862306a36Sopenharmony_ci	 */
12962306a36Sopenharmony_ci	if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||
13062306a36Sopenharmony_ci	    !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
13162306a36Sopenharmony_ci		return 0;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/*
13462306a36Sopenharmony_ci	 * The trusted.* namespace can only be accessed by privileged users.
13562306a36Sopenharmony_ci	 */
13662306a36Sopenharmony_ci	if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {
13762306a36Sopenharmony_ci		if (!capable(CAP_SYS_ADMIN))
13862306a36Sopenharmony_ci			return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
13962306a36Sopenharmony_ci		return 0;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/*
14362306a36Sopenharmony_ci	 * In the user.* namespace, only regular files and directories can have
14462306a36Sopenharmony_ci	 * extended attributes. For sticky directories, only the owner and
14562306a36Sopenharmony_ci	 * privileged users can write attributes.
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci	if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
14862306a36Sopenharmony_ci		if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
14962306a36Sopenharmony_ci			return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
15062306a36Sopenharmony_ci		if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
15162306a36Sopenharmony_ci		    (mask & MAY_WRITE) &&
15262306a36Sopenharmony_ci		    !inode_owner_or_capable(idmap, inode))
15362306a36Sopenharmony_ci			return -EPERM;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return inode_permission(idmap, inode, mask);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * Look for any handler that deals with the specified namespace.
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_ciint
16362306a36Sopenharmony_cixattr_supports_user_prefix(struct inode *inode)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	const struct xattr_handler **handlers = inode->i_sb->s_xattr;
16662306a36Sopenharmony_ci	const struct xattr_handler *handler;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (!(inode->i_opflags & IOP_XATTR)) {
16962306a36Sopenharmony_ci		if (unlikely(is_bad_inode(inode)))
17062306a36Sopenharmony_ci			return -EIO;
17162306a36Sopenharmony_ci		return -EOPNOTSUPP;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	for_each_xattr_handler(handlers, handler) {
17562306a36Sopenharmony_ci		if (!strncmp(xattr_prefix(handler), XATTR_USER_PREFIX,
17662306a36Sopenharmony_ci			     XATTR_USER_PREFIX_LEN))
17762306a36Sopenharmony_ci			return 0;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return -EOPNOTSUPP;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ciEXPORT_SYMBOL(xattr_supports_user_prefix);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ciint
18562306a36Sopenharmony_ci__vfs_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
18662306a36Sopenharmony_ci	       struct inode *inode, const char *name, const void *value,
18762306a36Sopenharmony_ci	       size_t size, int flags)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	const struct xattr_handler *handler;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (is_posix_acl_xattr(name))
19262306a36Sopenharmony_ci		return -EOPNOTSUPP;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	handler = xattr_resolve_name(inode, &name);
19562306a36Sopenharmony_ci	if (IS_ERR(handler))
19662306a36Sopenharmony_ci		return PTR_ERR(handler);
19762306a36Sopenharmony_ci	if (!handler->set)
19862306a36Sopenharmony_ci		return -EOPNOTSUPP;
19962306a36Sopenharmony_ci	if (size == 0)
20062306a36Sopenharmony_ci		value = "";  /* empty EA, do not remove */
20162306a36Sopenharmony_ci	return handler->set(handler, idmap, dentry, inode, name, value,
20262306a36Sopenharmony_ci			    size, flags);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ciEXPORT_SYMBOL(__vfs_setxattr);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/**
20762306a36Sopenharmony_ci *  __vfs_setxattr_noperm - perform setxattr operation without performing
20862306a36Sopenharmony_ci *  permission checks.
20962306a36Sopenharmony_ci *
21062306a36Sopenharmony_ci *  @idmap: idmap of the mount the inode was found from
21162306a36Sopenharmony_ci *  @dentry: object to perform setxattr on
21262306a36Sopenharmony_ci *  @name: xattr name to set
21362306a36Sopenharmony_ci *  @value: value to set @name to
21462306a36Sopenharmony_ci *  @size: size of @value
21562306a36Sopenharmony_ci *  @flags: flags to pass into filesystem operations
21662306a36Sopenharmony_ci *
21762306a36Sopenharmony_ci *  returns the result of the internal setxattr or setsecurity operations.
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci *  This function requires the caller to lock the inode's i_mutex before it
22062306a36Sopenharmony_ci *  is executed. It also assumes that the caller will make the appropriate
22162306a36Sopenharmony_ci *  permission checks.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_ciint __vfs_setxattr_noperm(struct mnt_idmap *idmap,
22462306a36Sopenharmony_ci			  struct dentry *dentry, const char *name,
22562306a36Sopenharmony_ci			  const void *value, size_t size, int flags)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct inode *inode = dentry->d_inode;
22862306a36Sopenharmony_ci	int error = -EAGAIN;
22962306a36Sopenharmony_ci	int issec = !strncmp(name, XATTR_SECURITY_PREFIX,
23062306a36Sopenharmony_ci				   XATTR_SECURITY_PREFIX_LEN);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (issec)
23362306a36Sopenharmony_ci		inode->i_flags &= ~S_NOSEC;
23462306a36Sopenharmony_ci	if (inode->i_opflags & IOP_XATTR) {
23562306a36Sopenharmony_ci		error = __vfs_setxattr(idmap, dentry, inode, name, value,
23662306a36Sopenharmony_ci				       size, flags);
23762306a36Sopenharmony_ci		if (!error) {
23862306a36Sopenharmony_ci			fsnotify_xattr(dentry);
23962306a36Sopenharmony_ci			security_inode_post_setxattr(dentry, name, value,
24062306a36Sopenharmony_ci						     size, flags);
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	} else {
24362306a36Sopenharmony_ci		if (unlikely(is_bad_inode(inode)))
24462306a36Sopenharmony_ci			return -EIO;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci	if (error == -EAGAIN) {
24762306a36Sopenharmony_ci		error = -EOPNOTSUPP;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		if (issec) {
25062306a36Sopenharmony_ci			const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci			error = security_inode_setsecurity(inode, suffix, value,
25362306a36Sopenharmony_ci							   size, flags);
25462306a36Sopenharmony_ci			if (!error)
25562306a36Sopenharmony_ci				fsnotify_xattr(dentry);
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return error;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/**
26362306a36Sopenharmony_ci * __vfs_setxattr_locked - set an extended attribute while holding the inode
26462306a36Sopenharmony_ci * lock
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci *  @idmap: idmap of the mount of the target inode
26762306a36Sopenharmony_ci *  @dentry: object to perform setxattr on
26862306a36Sopenharmony_ci *  @name: xattr name to set
26962306a36Sopenharmony_ci *  @value: value to set @name to
27062306a36Sopenharmony_ci *  @size: size of @value
27162306a36Sopenharmony_ci *  @flags: flags to pass into filesystem operations
27262306a36Sopenharmony_ci *  @delegated_inode: on return, will contain an inode pointer that
27362306a36Sopenharmony_ci *  a delegation was broken on, NULL if none.
27462306a36Sopenharmony_ci */
27562306a36Sopenharmony_ciint
27662306a36Sopenharmony_ci__vfs_setxattr_locked(struct mnt_idmap *idmap, struct dentry *dentry,
27762306a36Sopenharmony_ci		      const char *name, const void *value, size_t size,
27862306a36Sopenharmony_ci		      int flags, struct inode **delegated_inode)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct inode *inode = dentry->d_inode;
28162306a36Sopenharmony_ci	int error;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	error = xattr_permission(idmap, inode, name, MAY_WRITE);
28462306a36Sopenharmony_ci	if (error)
28562306a36Sopenharmony_ci		return error;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	error = security_inode_setxattr(idmap, dentry, name, value, size,
28862306a36Sopenharmony_ci					flags);
28962306a36Sopenharmony_ci	if (error)
29062306a36Sopenharmony_ci		goto out;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	error = try_break_deleg(inode, delegated_inode);
29362306a36Sopenharmony_ci	if (error)
29462306a36Sopenharmony_ci		goto out;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	error = __vfs_setxattr_noperm(idmap, dentry, name, value,
29762306a36Sopenharmony_ci				      size, flags);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ciout:
30062306a36Sopenharmony_ci	return error;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__vfs_setxattr_locked);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ciint
30562306a36Sopenharmony_civfs_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
30662306a36Sopenharmony_ci	     const char *name, const void *value, size_t size, int flags)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct inode *inode = dentry->d_inode;
30962306a36Sopenharmony_ci	struct inode *delegated_inode = NULL;
31062306a36Sopenharmony_ci	const void  *orig_value = value;
31162306a36Sopenharmony_ci	int error;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	if (size && strcmp(name, XATTR_NAME_CAPS) == 0) {
31462306a36Sopenharmony_ci		error = cap_convert_nscap(idmap, dentry, &value, size);
31562306a36Sopenharmony_ci		if (error < 0)
31662306a36Sopenharmony_ci			return error;
31762306a36Sopenharmony_ci		size = error;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ciretry_deleg:
32162306a36Sopenharmony_ci	inode_lock(inode);
32262306a36Sopenharmony_ci	error = __vfs_setxattr_locked(idmap, dentry, name, value, size,
32362306a36Sopenharmony_ci				      flags, &delegated_inode);
32462306a36Sopenharmony_ci	inode_unlock(inode);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (delegated_inode) {
32762306a36Sopenharmony_ci		error = break_deleg_wait(&delegated_inode);
32862306a36Sopenharmony_ci		if (!error)
32962306a36Sopenharmony_ci			goto retry_deleg;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci	if (value != orig_value)
33262306a36Sopenharmony_ci		kfree(value);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	return error;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_setxattr);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic ssize_t
33962306a36Sopenharmony_cixattr_getsecurity(struct mnt_idmap *idmap, struct inode *inode,
34062306a36Sopenharmony_ci		  const char *name, void *value, size_t size)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	void *buffer = NULL;
34362306a36Sopenharmony_ci	ssize_t len;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (!value || !size) {
34662306a36Sopenharmony_ci		len = security_inode_getsecurity(idmap, inode, name,
34762306a36Sopenharmony_ci						 &buffer, false);
34862306a36Sopenharmony_ci		goto out_noalloc;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	len = security_inode_getsecurity(idmap, inode, name, &buffer,
35262306a36Sopenharmony_ci					 true);
35362306a36Sopenharmony_ci	if (len < 0)
35462306a36Sopenharmony_ci		return len;
35562306a36Sopenharmony_ci	if (size < len) {
35662306a36Sopenharmony_ci		len = -ERANGE;
35762306a36Sopenharmony_ci		goto out;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci	memcpy(value, buffer, len);
36062306a36Sopenharmony_ciout:
36162306a36Sopenharmony_ci	kfree(buffer);
36262306a36Sopenharmony_ciout_noalloc:
36362306a36Sopenharmony_ci	return len;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci/*
36762306a36Sopenharmony_ci * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
36862306a36Sopenharmony_ci *
36962306a36Sopenharmony_ci * Allocate memory, if not already allocated, or re-allocate correct size,
37062306a36Sopenharmony_ci * before retrieving the extended attribute.  The xattr value buffer should
37162306a36Sopenharmony_ci * always be freed by the caller, even on error.
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * Returns the result of alloc, if failed, or the getxattr operation.
37462306a36Sopenharmony_ci */
37562306a36Sopenharmony_ciint
37662306a36Sopenharmony_civfs_getxattr_alloc(struct mnt_idmap *idmap, struct dentry *dentry,
37762306a36Sopenharmony_ci		   const char *name, char **xattr_value, size_t xattr_size,
37862306a36Sopenharmony_ci		   gfp_t flags)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	const struct xattr_handler *handler;
38162306a36Sopenharmony_ci	struct inode *inode = dentry->d_inode;
38262306a36Sopenharmony_ci	char *value = *xattr_value;
38362306a36Sopenharmony_ci	int error;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	error = xattr_permission(idmap, inode, name, MAY_READ);
38662306a36Sopenharmony_ci	if (error)
38762306a36Sopenharmony_ci		return error;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	handler = xattr_resolve_name(inode, &name);
39062306a36Sopenharmony_ci	if (IS_ERR(handler))
39162306a36Sopenharmony_ci		return PTR_ERR(handler);
39262306a36Sopenharmony_ci	if (!handler->get)
39362306a36Sopenharmony_ci		return -EOPNOTSUPP;
39462306a36Sopenharmony_ci	error = handler->get(handler, dentry, inode, name, NULL, 0);
39562306a36Sopenharmony_ci	if (error < 0)
39662306a36Sopenharmony_ci		return error;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (!value || (error > xattr_size)) {
39962306a36Sopenharmony_ci		value = krealloc(*xattr_value, error + 1, flags);
40062306a36Sopenharmony_ci		if (!value)
40162306a36Sopenharmony_ci			return -ENOMEM;
40262306a36Sopenharmony_ci		memset(value, 0, error + 1);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	error = handler->get(handler, dentry, inode, name, value, error);
40662306a36Sopenharmony_ci	*xattr_value = value;
40762306a36Sopenharmony_ci	return error;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cissize_t
41162306a36Sopenharmony_ci__vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
41262306a36Sopenharmony_ci	       void *value, size_t size)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	const struct xattr_handler *handler;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (is_posix_acl_xattr(name))
41762306a36Sopenharmony_ci		return -EOPNOTSUPP;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	handler = xattr_resolve_name(inode, &name);
42062306a36Sopenharmony_ci	if (IS_ERR(handler))
42162306a36Sopenharmony_ci		return PTR_ERR(handler);
42262306a36Sopenharmony_ci	if (!handler->get)
42362306a36Sopenharmony_ci		return -EOPNOTSUPP;
42462306a36Sopenharmony_ci	return handler->get(handler, dentry, inode, name, value, size);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ciEXPORT_SYMBOL(__vfs_getxattr);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cissize_t
42962306a36Sopenharmony_civfs_getxattr(struct mnt_idmap *idmap, struct dentry *dentry,
43062306a36Sopenharmony_ci	     const char *name, void *value, size_t size)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct inode *inode = dentry->d_inode;
43362306a36Sopenharmony_ci	int error;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	error = xattr_permission(idmap, inode, name, MAY_READ);
43662306a36Sopenharmony_ci	if (error)
43762306a36Sopenharmony_ci		return error;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	error = security_inode_getxattr(dentry, name);
44062306a36Sopenharmony_ci	if (error)
44162306a36Sopenharmony_ci		return error;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (!strncmp(name, XATTR_SECURITY_PREFIX,
44462306a36Sopenharmony_ci				XATTR_SECURITY_PREFIX_LEN)) {
44562306a36Sopenharmony_ci		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
44662306a36Sopenharmony_ci		int ret = xattr_getsecurity(idmap, inode, suffix, value,
44762306a36Sopenharmony_ci					    size);
44862306a36Sopenharmony_ci		/*
44962306a36Sopenharmony_ci		 * Only overwrite the return value if a security module
45062306a36Sopenharmony_ci		 * is actually active.
45162306a36Sopenharmony_ci		 */
45262306a36Sopenharmony_ci		if (ret == -EOPNOTSUPP)
45362306a36Sopenharmony_ci			goto nolsm;
45462306a36Sopenharmony_ci		return ret;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_cinolsm:
45762306a36Sopenharmony_ci	return __vfs_getxattr(dentry, inode, name, value, size);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_getxattr);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci/**
46262306a36Sopenharmony_ci * vfs_listxattr - retrieve \0 separated list of xattr names
46362306a36Sopenharmony_ci * @dentry: the dentry from whose inode the xattr names are retrieved
46462306a36Sopenharmony_ci * @list: buffer to store xattr names into
46562306a36Sopenharmony_ci * @size: size of the buffer
46662306a36Sopenharmony_ci *
46762306a36Sopenharmony_ci * This function returns the names of all xattrs associated with the
46862306a36Sopenharmony_ci * inode of @dentry.
46962306a36Sopenharmony_ci *
47062306a36Sopenharmony_ci * Note, for legacy reasons the vfs_listxattr() function lists POSIX
47162306a36Sopenharmony_ci * ACLs as well. Since POSIX ACLs are decoupled from IOP_XATTR the
47262306a36Sopenharmony_ci * vfs_listxattr() function doesn't check for this flag since a
47362306a36Sopenharmony_ci * filesystem could implement POSIX ACLs without implementing any other
47462306a36Sopenharmony_ci * xattrs.
47562306a36Sopenharmony_ci *
47662306a36Sopenharmony_ci * However, since all codepaths that remove IOP_XATTR also assign of
47762306a36Sopenharmony_ci * inode operations that either don't implement or implement a stub
47862306a36Sopenharmony_ci * ->listxattr() operation.
47962306a36Sopenharmony_ci *
48062306a36Sopenharmony_ci * Return: On success, the size of the buffer that was used. On error a
48162306a36Sopenharmony_ci *         negative error code.
48262306a36Sopenharmony_ci */
48362306a36Sopenharmony_cissize_t
48462306a36Sopenharmony_civfs_listxattr(struct dentry *dentry, char *list, size_t size)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
48762306a36Sopenharmony_ci	ssize_t error;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	error = security_inode_listxattr(dentry);
49062306a36Sopenharmony_ci	if (error)
49162306a36Sopenharmony_ci		return error;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (inode->i_op->listxattr) {
49462306a36Sopenharmony_ci		error = inode->i_op->listxattr(dentry, list, size);
49562306a36Sopenharmony_ci	} else {
49662306a36Sopenharmony_ci		error = security_inode_listsecurity(inode, list, size);
49762306a36Sopenharmony_ci		if (size && error > size)
49862306a36Sopenharmony_ci			error = -ERANGE;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci	return error;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_listxattr);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ciint
50562306a36Sopenharmony_ci__vfs_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
50662306a36Sopenharmony_ci		  const char *name)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
50962306a36Sopenharmony_ci	const struct xattr_handler *handler;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (is_posix_acl_xattr(name))
51262306a36Sopenharmony_ci		return -EOPNOTSUPP;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	handler = xattr_resolve_name(inode, &name);
51562306a36Sopenharmony_ci	if (IS_ERR(handler))
51662306a36Sopenharmony_ci		return PTR_ERR(handler);
51762306a36Sopenharmony_ci	if (!handler->set)
51862306a36Sopenharmony_ci		return -EOPNOTSUPP;
51962306a36Sopenharmony_ci	return handler->set(handler, idmap, dentry, inode, name, NULL, 0,
52062306a36Sopenharmony_ci			    XATTR_REPLACE);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ciEXPORT_SYMBOL(__vfs_removexattr);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/**
52562306a36Sopenharmony_ci * __vfs_removexattr_locked - set an extended attribute while holding the inode
52662306a36Sopenharmony_ci * lock
52762306a36Sopenharmony_ci *
52862306a36Sopenharmony_ci *  @idmap: idmap of the mount of the target inode
52962306a36Sopenharmony_ci *  @dentry: object to perform setxattr on
53062306a36Sopenharmony_ci *  @name: name of xattr to remove
53162306a36Sopenharmony_ci *  @delegated_inode: on return, will contain an inode pointer that
53262306a36Sopenharmony_ci *  a delegation was broken on, NULL if none.
53362306a36Sopenharmony_ci */
53462306a36Sopenharmony_ciint
53562306a36Sopenharmony_ci__vfs_removexattr_locked(struct mnt_idmap *idmap,
53662306a36Sopenharmony_ci			 struct dentry *dentry, const char *name,
53762306a36Sopenharmony_ci			 struct inode **delegated_inode)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct inode *inode = dentry->d_inode;
54062306a36Sopenharmony_ci	int error;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	error = xattr_permission(idmap, inode, name, MAY_WRITE);
54362306a36Sopenharmony_ci	if (error)
54462306a36Sopenharmony_ci		return error;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	error = security_inode_removexattr(idmap, dentry, name);
54762306a36Sopenharmony_ci	if (error)
54862306a36Sopenharmony_ci		goto out;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	error = try_break_deleg(inode, delegated_inode);
55162306a36Sopenharmony_ci	if (error)
55262306a36Sopenharmony_ci		goto out;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	error = __vfs_removexattr(idmap, dentry, name);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (!error) {
55762306a36Sopenharmony_ci		fsnotify_xattr(dentry);
55862306a36Sopenharmony_ci		evm_inode_post_removexattr(dentry, name);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ciout:
56262306a36Sopenharmony_ci	return error;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__vfs_removexattr_locked);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ciint
56762306a36Sopenharmony_civfs_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
56862306a36Sopenharmony_ci		const char *name)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct inode *inode = dentry->d_inode;
57162306a36Sopenharmony_ci	struct inode *delegated_inode = NULL;
57262306a36Sopenharmony_ci	int error;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ciretry_deleg:
57562306a36Sopenharmony_ci	inode_lock(inode);
57662306a36Sopenharmony_ci	error = __vfs_removexattr_locked(idmap, dentry,
57762306a36Sopenharmony_ci					 name, &delegated_inode);
57862306a36Sopenharmony_ci	inode_unlock(inode);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (delegated_inode) {
58162306a36Sopenharmony_ci		error = break_deleg_wait(&delegated_inode);
58262306a36Sopenharmony_ci		if (!error)
58362306a36Sopenharmony_ci			goto retry_deleg;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	return error;
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vfs_removexattr);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/*
59162306a36Sopenharmony_ci * Extended attribute SET operations
59262306a36Sopenharmony_ci */
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ciint setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	int error;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (ctx->flags & ~(XATTR_CREATE|XATTR_REPLACE))
59962306a36Sopenharmony_ci		return -EINVAL;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	error = strncpy_from_user(ctx->kname->name, name,
60262306a36Sopenharmony_ci				sizeof(ctx->kname->name));
60362306a36Sopenharmony_ci	if (error == 0 || error == sizeof(ctx->kname->name))
60462306a36Sopenharmony_ci		return  -ERANGE;
60562306a36Sopenharmony_ci	if (error < 0)
60662306a36Sopenharmony_ci		return error;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	error = 0;
60962306a36Sopenharmony_ci	if (ctx->size) {
61062306a36Sopenharmony_ci		if (ctx->size > XATTR_SIZE_MAX)
61162306a36Sopenharmony_ci			return -E2BIG;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci		ctx->kvalue = vmemdup_user(ctx->cvalue, ctx->size);
61462306a36Sopenharmony_ci		if (IS_ERR(ctx->kvalue)) {
61562306a36Sopenharmony_ci			error = PTR_ERR(ctx->kvalue);
61662306a36Sopenharmony_ci			ctx->kvalue = NULL;
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	return error;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ciint do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
62462306a36Sopenharmony_ci		struct xattr_ctx *ctx)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	if (is_posix_acl_xattr(ctx->kname->name))
62762306a36Sopenharmony_ci		return do_set_acl(idmap, dentry, ctx->kname->name,
62862306a36Sopenharmony_ci				  ctx->kvalue, ctx->size);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return vfs_setxattr(idmap, dentry, ctx->kname->name,
63162306a36Sopenharmony_ci			ctx->kvalue, ctx->size, ctx->flags);
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic long
63562306a36Sopenharmony_cisetxattr(struct mnt_idmap *idmap, struct dentry *d,
63662306a36Sopenharmony_ci	const char __user *name, const void __user *value, size_t size,
63762306a36Sopenharmony_ci	int flags)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct xattr_name kname;
64062306a36Sopenharmony_ci	struct xattr_ctx ctx = {
64162306a36Sopenharmony_ci		.cvalue   = value,
64262306a36Sopenharmony_ci		.kvalue   = NULL,
64362306a36Sopenharmony_ci		.size     = size,
64462306a36Sopenharmony_ci		.kname    = &kname,
64562306a36Sopenharmony_ci		.flags    = flags,
64662306a36Sopenharmony_ci	};
64762306a36Sopenharmony_ci	int error;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	error = setxattr_copy(name, &ctx);
65062306a36Sopenharmony_ci	if (error)
65162306a36Sopenharmony_ci		return error;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	error = do_setxattr(idmap, d, &ctx);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	kvfree(ctx.kvalue);
65662306a36Sopenharmony_ci	return error;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic int path_setxattr(const char __user *pathname,
66062306a36Sopenharmony_ci			 const char __user *name, const void __user *value,
66162306a36Sopenharmony_ci			 size_t size, int flags, unsigned int lookup_flags)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	struct path path;
66462306a36Sopenharmony_ci	int error;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ciretry:
66762306a36Sopenharmony_ci	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
66862306a36Sopenharmony_ci	if (error)
66962306a36Sopenharmony_ci		return error;
67062306a36Sopenharmony_ci	error = mnt_want_write(path.mnt);
67162306a36Sopenharmony_ci	if (!error) {
67262306a36Sopenharmony_ci		error = setxattr(mnt_idmap(path.mnt), path.dentry, name,
67362306a36Sopenharmony_ci				 value, size, flags);
67462306a36Sopenharmony_ci		mnt_drop_write(path.mnt);
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci	path_put(&path);
67762306a36Sopenharmony_ci	if (retry_estale(error, lookup_flags)) {
67862306a36Sopenharmony_ci		lookup_flags |= LOOKUP_REVAL;
67962306a36Sopenharmony_ci		goto retry;
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci	return error;
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ciSYSCALL_DEFINE5(setxattr, const char __user *, pathname,
68562306a36Sopenharmony_ci		const char __user *, name, const void __user *, value,
68662306a36Sopenharmony_ci		size_t, size, int, flags)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	return path_setxattr(pathname, name, value, size, flags, LOOKUP_FOLLOW);
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ciSYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
69262306a36Sopenharmony_ci		const char __user *, name, const void __user *, value,
69362306a36Sopenharmony_ci		size_t, size, int, flags)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	return path_setxattr(pathname, name, value, size, flags, 0);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ciSYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
69962306a36Sopenharmony_ci		const void __user *,value, size_t, size, int, flags)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct fd f = fdget(fd);
70262306a36Sopenharmony_ci	int error = -EBADF;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (!f.file)
70562306a36Sopenharmony_ci		return error;
70662306a36Sopenharmony_ci	audit_file(f.file);
70762306a36Sopenharmony_ci	error = mnt_want_write_file(f.file);
70862306a36Sopenharmony_ci	if (!error) {
70962306a36Sopenharmony_ci		error = setxattr(file_mnt_idmap(f.file),
71062306a36Sopenharmony_ci				 f.file->f_path.dentry, name,
71162306a36Sopenharmony_ci				 value, size, flags);
71262306a36Sopenharmony_ci		mnt_drop_write_file(f.file);
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci	fdput(f);
71562306a36Sopenharmony_ci	return error;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci/*
71962306a36Sopenharmony_ci * Extended attribute GET operations
72062306a36Sopenharmony_ci */
72162306a36Sopenharmony_cissize_t
72262306a36Sopenharmony_cido_getxattr(struct mnt_idmap *idmap, struct dentry *d,
72362306a36Sopenharmony_ci	struct xattr_ctx *ctx)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	ssize_t error;
72662306a36Sopenharmony_ci	char *kname = ctx->kname->name;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (ctx->size) {
72962306a36Sopenharmony_ci		if (ctx->size > XATTR_SIZE_MAX)
73062306a36Sopenharmony_ci			ctx->size = XATTR_SIZE_MAX;
73162306a36Sopenharmony_ci		ctx->kvalue = kvzalloc(ctx->size, GFP_KERNEL);
73262306a36Sopenharmony_ci		if (!ctx->kvalue)
73362306a36Sopenharmony_ci			return -ENOMEM;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (is_posix_acl_xattr(ctx->kname->name))
73762306a36Sopenharmony_ci		error = do_get_acl(idmap, d, kname, ctx->kvalue, ctx->size);
73862306a36Sopenharmony_ci	else
73962306a36Sopenharmony_ci		error = vfs_getxattr(idmap, d, kname, ctx->kvalue, ctx->size);
74062306a36Sopenharmony_ci	if (error > 0) {
74162306a36Sopenharmony_ci		if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
74262306a36Sopenharmony_ci			error = -EFAULT;
74362306a36Sopenharmony_ci	} else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) {
74462306a36Sopenharmony_ci		/* The file system tried to returned a value bigger
74562306a36Sopenharmony_ci		   than XATTR_SIZE_MAX bytes. Not possible. */
74662306a36Sopenharmony_ci		error = -E2BIG;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	return error;
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic ssize_t
75362306a36Sopenharmony_cigetxattr(struct mnt_idmap *idmap, struct dentry *d,
75462306a36Sopenharmony_ci	 const char __user *name, void __user *value, size_t size)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	ssize_t error;
75762306a36Sopenharmony_ci	struct xattr_name kname;
75862306a36Sopenharmony_ci	struct xattr_ctx ctx = {
75962306a36Sopenharmony_ci		.value    = value,
76062306a36Sopenharmony_ci		.kvalue   = NULL,
76162306a36Sopenharmony_ci		.size     = size,
76262306a36Sopenharmony_ci		.kname    = &kname,
76362306a36Sopenharmony_ci		.flags    = 0,
76462306a36Sopenharmony_ci	};
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	error = strncpy_from_user(kname.name, name, sizeof(kname.name));
76762306a36Sopenharmony_ci	if (error == 0 || error == sizeof(kname.name))
76862306a36Sopenharmony_ci		error = -ERANGE;
76962306a36Sopenharmony_ci	if (error < 0)
77062306a36Sopenharmony_ci		return error;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	error =  do_getxattr(idmap, d, &ctx);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	kvfree(ctx.kvalue);
77562306a36Sopenharmony_ci	return error;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic ssize_t path_getxattr(const char __user *pathname,
77962306a36Sopenharmony_ci			     const char __user *name, void __user *value,
78062306a36Sopenharmony_ci			     size_t size, unsigned int lookup_flags)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	struct path path;
78362306a36Sopenharmony_ci	ssize_t error;
78462306a36Sopenharmony_ciretry:
78562306a36Sopenharmony_ci	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
78662306a36Sopenharmony_ci	if (error)
78762306a36Sopenharmony_ci		return error;
78862306a36Sopenharmony_ci	error = getxattr(mnt_idmap(path.mnt), path.dentry, name, value, size);
78962306a36Sopenharmony_ci	path_put(&path);
79062306a36Sopenharmony_ci	if (retry_estale(error, lookup_flags)) {
79162306a36Sopenharmony_ci		lookup_flags |= LOOKUP_REVAL;
79262306a36Sopenharmony_ci		goto retry;
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci	return error;
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ciSYSCALL_DEFINE4(getxattr, const char __user *, pathname,
79862306a36Sopenharmony_ci		const char __user *, name, void __user *, value, size_t, size)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	return path_getxattr(pathname, name, value, size, LOOKUP_FOLLOW);
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ciSYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
80462306a36Sopenharmony_ci		const char __user *, name, void __user *, value, size_t, size)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	return path_getxattr(pathname, name, value, size, 0);
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ciSYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
81062306a36Sopenharmony_ci		void __user *, value, size_t, size)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	struct fd f = fdget(fd);
81362306a36Sopenharmony_ci	ssize_t error = -EBADF;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (!f.file)
81662306a36Sopenharmony_ci		return error;
81762306a36Sopenharmony_ci	audit_file(f.file);
81862306a36Sopenharmony_ci	error = getxattr(file_mnt_idmap(f.file), f.file->f_path.dentry,
81962306a36Sopenharmony_ci			 name, value, size);
82062306a36Sopenharmony_ci	fdput(f);
82162306a36Sopenharmony_ci	return error;
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci/*
82562306a36Sopenharmony_ci * Extended attribute LIST operations
82662306a36Sopenharmony_ci */
82762306a36Sopenharmony_cistatic ssize_t
82862306a36Sopenharmony_cilistxattr(struct dentry *d, char __user *list, size_t size)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	ssize_t error;
83162306a36Sopenharmony_ci	char *klist = NULL;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	if (size) {
83462306a36Sopenharmony_ci		if (size > XATTR_LIST_MAX)
83562306a36Sopenharmony_ci			size = XATTR_LIST_MAX;
83662306a36Sopenharmony_ci		klist = kvmalloc(size, GFP_KERNEL);
83762306a36Sopenharmony_ci		if (!klist)
83862306a36Sopenharmony_ci			return -ENOMEM;
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	error = vfs_listxattr(d, klist, size);
84262306a36Sopenharmony_ci	if (error > 0) {
84362306a36Sopenharmony_ci		if (size && copy_to_user(list, klist, error))
84462306a36Sopenharmony_ci			error = -EFAULT;
84562306a36Sopenharmony_ci	} else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
84662306a36Sopenharmony_ci		/* The file system tried to returned a list bigger
84762306a36Sopenharmony_ci		   than XATTR_LIST_MAX bytes. Not possible. */
84862306a36Sopenharmony_ci		error = -E2BIG;
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	kvfree(klist);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return error;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic ssize_t path_listxattr(const char __user *pathname, char __user *list,
85762306a36Sopenharmony_ci			      size_t size, unsigned int lookup_flags)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct path path;
86062306a36Sopenharmony_ci	ssize_t error;
86162306a36Sopenharmony_ciretry:
86262306a36Sopenharmony_ci	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
86362306a36Sopenharmony_ci	if (error)
86462306a36Sopenharmony_ci		return error;
86562306a36Sopenharmony_ci	error = listxattr(path.dentry, list, size);
86662306a36Sopenharmony_ci	path_put(&path);
86762306a36Sopenharmony_ci	if (retry_estale(error, lookup_flags)) {
86862306a36Sopenharmony_ci		lookup_flags |= LOOKUP_REVAL;
86962306a36Sopenharmony_ci		goto retry;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci	return error;
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ciSYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
87562306a36Sopenharmony_ci		size_t, size)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	return path_listxattr(pathname, list, size, LOOKUP_FOLLOW);
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ciSYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
88162306a36Sopenharmony_ci		size_t, size)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	return path_listxattr(pathname, list, size, 0);
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ciSYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	struct fd f = fdget(fd);
88962306a36Sopenharmony_ci	ssize_t error = -EBADF;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	if (!f.file)
89262306a36Sopenharmony_ci		return error;
89362306a36Sopenharmony_ci	audit_file(f.file);
89462306a36Sopenharmony_ci	error = listxattr(f.file->f_path.dentry, list, size);
89562306a36Sopenharmony_ci	fdput(f);
89662306a36Sopenharmony_ci	return error;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci/*
90062306a36Sopenharmony_ci * Extended attribute REMOVE operations
90162306a36Sopenharmony_ci */
90262306a36Sopenharmony_cistatic long
90362306a36Sopenharmony_ciremovexattr(struct mnt_idmap *idmap, struct dentry *d,
90462306a36Sopenharmony_ci	    const char __user *name)
90562306a36Sopenharmony_ci{
90662306a36Sopenharmony_ci	int error;
90762306a36Sopenharmony_ci	char kname[XATTR_NAME_MAX + 1];
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	error = strncpy_from_user(kname, name, sizeof(kname));
91062306a36Sopenharmony_ci	if (error == 0 || error == sizeof(kname))
91162306a36Sopenharmony_ci		error = -ERANGE;
91262306a36Sopenharmony_ci	if (error < 0)
91362306a36Sopenharmony_ci		return error;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (is_posix_acl_xattr(kname))
91662306a36Sopenharmony_ci		return vfs_remove_acl(idmap, d, kname);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	return vfs_removexattr(idmap, d, kname);
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_cistatic int path_removexattr(const char __user *pathname,
92262306a36Sopenharmony_ci			    const char __user *name, unsigned int lookup_flags)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	struct path path;
92562306a36Sopenharmony_ci	int error;
92662306a36Sopenharmony_ciretry:
92762306a36Sopenharmony_ci	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
92862306a36Sopenharmony_ci	if (error)
92962306a36Sopenharmony_ci		return error;
93062306a36Sopenharmony_ci	error = mnt_want_write(path.mnt);
93162306a36Sopenharmony_ci	if (!error) {
93262306a36Sopenharmony_ci		error = removexattr(mnt_idmap(path.mnt), path.dentry, name);
93362306a36Sopenharmony_ci		mnt_drop_write(path.mnt);
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci	path_put(&path);
93662306a36Sopenharmony_ci	if (retry_estale(error, lookup_flags)) {
93762306a36Sopenharmony_ci		lookup_flags |= LOOKUP_REVAL;
93862306a36Sopenharmony_ci		goto retry;
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci	return error;
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ciSYSCALL_DEFINE2(removexattr, const char __user *, pathname,
94462306a36Sopenharmony_ci		const char __user *, name)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	return path_removexattr(pathname, name, LOOKUP_FOLLOW);
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ciSYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
95062306a36Sopenharmony_ci		const char __user *, name)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	return path_removexattr(pathname, name, 0);
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ciSYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct fd f = fdget(fd);
95862306a36Sopenharmony_ci	int error = -EBADF;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	if (!f.file)
96162306a36Sopenharmony_ci		return error;
96262306a36Sopenharmony_ci	audit_file(f.file);
96362306a36Sopenharmony_ci	error = mnt_want_write_file(f.file);
96462306a36Sopenharmony_ci	if (!error) {
96562306a36Sopenharmony_ci		error = removexattr(file_mnt_idmap(f.file),
96662306a36Sopenharmony_ci				    f.file->f_path.dentry, name);
96762306a36Sopenharmony_ci		mnt_drop_write_file(f.file);
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci	fdput(f);
97062306a36Sopenharmony_ci	return error;
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ciint xattr_list_one(char **buffer, ssize_t *remaining_size, const char *name)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	size_t len;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	len = strlen(name) + 1;
97862306a36Sopenharmony_ci	if (*buffer) {
97962306a36Sopenharmony_ci		if (*remaining_size < len)
98062306a36Sopenharmony_ci			return -ERANGE;
98162306a36Sopenharmony_ci		memcpy(*buffer, name, len);
98262306a36Sopenharmony_ci		*buffer += len;
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci	*remaining_size -= len;
98562306a36Sopenharmony_ci	return 0;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci/**
98962306a36Sopenharmony_ci * generic_listxattr - run through a dentry's xattr list() operations
99062306a36Sopenharmony_ci * @dentry: dentry to list the xattrs
99162306a36Sopenharmony_ci * @buffer: result buffer
99262306a36Sopenharmony_ci * @buffer_size: size of @buffer
99362306a36Sopenharmony_ci *
99462306a36Sopenharmony_ci * Combine the results of the list() operation from every xattr_handler in the
99562306a36Sopenharmony_ci * xattr_handler stack.
99662306a36Sopenharmony_ci *
99762306a36Sopenharmony_ci * Note that this will not include the entries for POSIX ACLs.
99862306a36Sopenharmony_ci */
99962306a36Sopenharmony_cissize_t
100062306a36Sopenharmony_cigeneric_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	const struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
100362306a36Sopenharmony_ci	ssize_t remaining_size = buffer_size;
100462306a36Sopenharmony_ci	int err = 0;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	for_each_xattr_handler(handlers, handler) {
100762306a36Sopenharmony_ci		if (!handler->name || (handler->list && !handler->list(dentry)))
100862306a36Sopenharmony_ci			continue;
100962306a36Sopenharmony_ci		err = xattr_list_one(&buffer, &remaining_size, handler->name);
101062306a36Sopenharmony_ci		if (err)
101162306a36Sopenharmony_ci			return err;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	return err ? err : buffer_size - remaining_size;
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ciEXPORT_SYMBOL(generic_listxattr);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci/**
101962306a36Sopenharmony_ci * xattr_full_name  -  Compute full attribute name from suffix
102062306a36Sopenharmony_ci *
102162306a36Sopenharmony_ci * @handler:	handler of the xattr_handler operation
102262306a36Sopenharmony_ci * @name:	name passed to the xattr_handler operation
102362306a36Sopenharmony_ci *
102462306a36Sopenharmony_ci * The get and set xattr handler operations are called with the remainder of
102562306a36Sopenharmony_ci * the attribute name after skipping the handler's prefix: for example, "foo"
102662306a36Sopenharmony_ci * is passed to the get operation of a handler with prefix "user." to get
102762306a36Sopenharmony_ci * attribute "user.foo".  The full name is still "there" in the name though.
102862306a36Sopenharmony_ci *
102962306a36Sopenharmony_ci * Note: the list xattr handler operation when called from the vfs is passed a
103062306a36Sopenharmony_ci * NULL name; some file systems use this operation internally, with varying
103162306a36Sopenharmony_ci * semantics.
103262306a36Sopenharmony_ci */
103362306a36Sopenharmony_ciconst char *xattr_full_name(const struct xattr_handler *handler,
103462306a36Sopenharmony_ci			    const char *name)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	size_t prefix_len = strlen(xattr_prefix(handler));
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	return name - prefix_len;
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ciEXPORT_SYMBOL(xattr_full_name);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci/**
104362306a36Sopenharmony_ci * simple_xattr_space - estimate the memory used by a simple xattr
104462306a36Sopenharmony_ci * @name: the full name of the xattr
104562306a36Sopenharmony_ci * @size: the size of its value
104662306a36Sopenharmony_ci *
104762306a36Sopenharmony_ci * This takes no account of how much larger the two slab objects actually are:
104862306a36Sopenharmony_ci * that would depend on the slab implementation, when what is required is a
104962306a36Sopenharmony_ci * deterministic number, which grows with name length and size and quantity.
105062306a36Sopenharmony_ci *
105162306a36Sopenharmony_ci * Return: The approximate number of bytes of memory used by such an xattr.
105262306a36Sopenharmony_ci */
105362306a36Sopenharmony_cisize_t simple_xattr_space(const char *name, size_t size)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	/*
105662306a36Sopenharmony_ci	 * Use "40" instead of sizeof(struct simple_xattr), to return the
105762306a36Sopenharmony_ci	 * same result on 32-bit and 64-bit, and even if simple_xattr grows.
105862306a36Sopenharmony_ci	 */
105962306a36Sopenharmony_ci	return 40 + size + strlen(name);
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci/**
106362306a36Sopenharmony_ci * simple_xattr_free - free an xattr object
106462306a36Sopenharmony_ci * @xattr: the xattr object
106562306a36Sopenharmony_ci *
106662306a36Sopenharmony_ci * Free the xattr object. Can handle @xattr being NULL.
106762306a36Sopenharmony_ci */
106862306a36Sopenharmony_civoid simple_xattr_free(struct simple_xattr *xattr)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	if (xattr)
107162306a36Sopenharmony_ci		kfree(xattr->name);
107262306a36Sopenharmony_ci	kvfree(xattr);
107362306a36Sopenharmony_ci}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci/**
107662306a36Sopenharmony_ci * simple_xattr_alloc - allocate new xattr object
107762306a36Sopenharmony_ci * @value: value of the xattr object
107862306a36Sopenharmony_ci * @size: size of @value
107962306a36Sopenharmony_ci *
108062306a36Sopenharmony_ci * Allocate a new xattr object and initialize respective members. The caller is
108162306a36Sopenharmony_ci * responsible for handling the name of the xattr.
108262306a36Sopenharmony_ci *
108362306a36Sopenharmony_ci * Return: On success a new xattr object is returned. On failure NULL is
108462306a36Sopenharmony_ci * returned.
108562306a36Sopenharmony_ci */
108662306a36Sopenharmony_cistruct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	struct simple_xattr *new_xattr;
108962306a36Sopenharmony_ci	size_t len;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	/* wrap around? */
109262306a36Sopenharmony_ci	len = sizeof(*new_xattr) + size;
109362306a36Sopenharmony_ci	if (len < sizeof(*new_xattr))
109462306a36Sopenharmony_ci		return NULL;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	new_xattr = kvmalloc(len, GFP_KERNEL_ACCOUNT);
109762306a36Sopenharmony_ci	if (!new_xattr)
109862306a36Sopenharmony_ci		return NULL;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	new_xattr->size = size;
110162306a36Sopenharmony_ci	memcpy(new_xattr->value, value, size);
110262306a36Sopenharmony_ci	return new_xattr;
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci/**
110662306a36Sopenharmony_ci * rbtree_simple_xattr_cmp - compare xattr name with current rbtree xattr entry
110762306a36Sopenharmony_ci * @key: xattr name
110862306a36Sopenharmony_ci * @node: current node
110962306a36Sopenharmony_ci *
111062306a36Sopenharmony_ci * Compare the xattr name with the xattr name attached to @node in the rbtree.
111162306a36Sopenharmony_ci *
111262306a36Sopenharmony_ci * Return: Negative value if continuing left, positive if continuing right, 0
111362306a36Sopenharmony_ci * if the xattr attached to @node matches @key.
111462306a36Sopenharmony_ci */
111562306a36Sopenharmony_cistatic int rbtree_simple_xattr_cmp(const void *key, const struct rb_node *node)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	const char *xattr_name = key;
111862306a36Sopenharmony_ci	const struct simple_xattr *xattr;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	xattr = rb_entry(node, struct simple_xattr, rb_node);
112162306a36Sopenharmony_ci	return strcmp(xattr->name, xattr_name);
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci/**
112562306a36Sopenharmony_ci * rbtree_simple_xattr_node_cmp - compare two xattr rbtree nodes
112662306a36Sopenharmony_ci * @new_node: new node
112762306a36Sopenharmony_ci * @node: current node
112862306a36Sopenharmony_ci *
112962306a36Sopenharmony_ci * Compare the xattr attached to @new_node with the xattr attached to @node.
113062306a36Sopenharmony_ci *
113162306a36Sopenharmony_ci * Return: Negative value if continuing left, positive if continuing right, 0
113262306a36Sopenharmony_ci * if the xattr attached to @new_node matches the xattr attached to @node.
113362306a36Sopenharmony_ci */
113462306a36Sopenharmony_cistatic int rbtree_simple_xattr_node_cmp(struct rb_node *new_node,
113562306a36Sopenharmony_ci					const struct rb_node *node)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	struct simple_xattr *xattr;
113862306a36Sopenharmony_ci	xattr = rb_entry(new_node, struct simple_xattr, rb_node);
113962306a36Sopenharmony_ci	return rbtree_simple_xattr_cmp(xattr->name, node);
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci/**
114362306a36Sopenharmony_ci * simple_xattr_get - get an xattr object
114462306a36Sopenharmony_ci * @xattrs: the header of the xattr object
114562306a36Sopenharmony_ci * @name: the name of the xattr to retrieve
114662306a36Sopenharmony_ci * @buffer: the buffer to store the value into
114762306a36Sopenharmony_ci * @size: the size of @buffer
114862306a36Sopenharmony_ci *
114962306a36Sopenharmony_ci * Try to find and retrieve the xattr object associated with @name.
115062306a36Sopenharmony_ci * If @buffer is provided store the value of @xattr in @buffer
115162306a36Sopenharmony_ci * otherwise just return the length. The size of @buffer is limited
115262306a36Sopenharmony_ci * to XATTR_SIZE_MAX which currently is 65536.
115362306a36Sopenharmony_ci *
115462306a36Sopenharmony_ci * Return: On success the length of the xattr value is returned. On error a
115562306a36Sopenharmony_ci * negative error code is returned.
115662306a36Sopenharmony_ci */
115762306a36Sopenharmony_ciint simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
115862306a36Sopenharmony_ci		     void *buffer, size_t size)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	struct simple_xattr *xattr = NULL;
116162306a36Sopenharmony_ci	struct rb_node *rbp;
116262306a36Sopenharmony_ci	int ret = -ENODATA;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	read_lock(&xattrs->lock);
116562306a36Sopenharmony_ci	rbp = rb_find(name, &xattrs->rb_root, rbtree_simple_xattr_cmp);
116662306a36Sopenharmony_ci	if (rbp) {
116762306a36Sopenharmony_ci		xattr = rb_entry(rbp, struct simple_xattr, rb_node);
116862306a36Sopenharmony_ci		ret = xattr->size;
116962306a36Sopenharmony_ci		if (buffer) {
117062306a36Sopenharmony_ci			if (size < xattr->size)
117162306a36Sopenharmony_ci				ret = -ERANGE;
117262306a36Sopenharmony_ci			else
117362306a36Sopenharmony_ci				memcpy(buffer, xattr->value, xattr->size);
117462306a36Sopenharmony_ci		}
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci	read_unlock(&xattrs->lock);
117762306a36Sopenharmony_ci	return ret;
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci/**
118162306a36Sopenharmony_ci * simple_xattr_set - set an xattr object
118262306a36Sopenharmony_ci * @xattrs: the header of the xattr object
118362306a36Sopenharmony_ci * @name: the name of the xattr to retrieve
118462306a36Sopenharmony_ci * @value: the value to store along the xattr
118562306a36Sopenharmony_ci * @size: the size of @value
118662306a36Sopenharmony_ci * @flags: the flags determining how to set the xattr
118762306a36Sopenharmony_ci *
118862306a36Sopenharmony_ci * Set a new xattr object.
118962306a36Sopenharmony_ci * If @value is passed a new xattr object will be allocated. If XATTR_REPLACE
119062306a36Sopenharmony_ci * is specified in @flags a matching xattr object for @name must already exist.
119162306a36Sopenharmony_ci * If it does it will be replaced with the new xattr object. If it doesn't we
119262306a36Sopenharmony_ci * fail. If XATTR_CREATE is specified and a matching xattr does already exist
119362306a36Sopenharmony_ci * we fail. If it doesn't we create a new xattr. If @flags is zero we simply
119462306a36Sopenharmony_ci * insert the new xattr replacing any existing one.
119562306a36Sopenharmony_ci *
119662306a36Sopenharmony_ci * If @value is empty and a matching xattr object is found we delete it if
119762306a36Sopenharmony_ci * XATTR_REPLACE is specified in @flags or @flags is zero.
119862306a36Sopenharmony_ci *
119962306a36Sopenharmony_ci * If @value is empty and no matching xattr object for @name is found we do
120062306a36Sopenharmony_ci * nothing if XATTR_CREATE is specified in @flags or @flags is zero. For
120162306a36Sopenharmony_ci * XATTR_REPLACE we fail as mentioned above.
120262306a36Sopenharmony_ci *
120362306a36Sopenharmony_ci * Return: On success, the removed or replaced xattr is returned, to be freed
120462306a36Sopenharmony_ci * by the caller; or NULL if none. On failure a negative error code is returned.
120562306a36Sopenharmony_ci */
120662306a36Sopenharmony_cistruct simple_xattr *simple_xattr_set(struct simple_xattrs *xattrs,
120762306a36Sopenharmony_ci				      const char *name, const void *value,
120862306a36Sopenharmony_ci				      size_t size, int flags)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	struct simple_xattr *old_xattr = NULL, *new_xattr = NULL;
121162306a36Sopenharmony_ci	struct rb_node *parent = NULL, **rbp;
121262306a36Sopenharmony_ci	int err = 0, ret;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/* value == NULL means remove */
121562306a36Sopenharmony_ci	if (value) {
121662306a36Sopenharmony_ci		new_xattr = simple_xattr_alloc(value, size);
121762306a36Sopenharmony_ci		if (!new_xattr)
121862306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci		new_xattr->name = kstrdup(name, GFP_KERNEL_ACCOUNT);
122162306a36Sopenharmony_ci		if (!new_xattr->name) {
122262306a36Sopenharmony_ci			simple_xattr_free(new_xattr);
122362306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
122462306a36Sopenharmony_ci		}
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	write_lock(&xattrs->lock);
122862306a36Sopenharmony_ci	rbp = &xattrs->rb_root.rb_node;
122962306a36Sopenharmony_ci	while (*rbp) {
123062306a36Sopenharmony_ci		parent = *rbp;
123162306a36Sopenharmony_ci		ret = rbtree_simple_xattr_cmp(name, *rbp);
123262306a36Sopenharmony_ci		if (ret < 0)
123362306a36Sopenharmony_ci			rbp = &(*rbp)->rb_left;
123462306a36Sopenharmony_ci		else if (ret > 0)
123562306a36Sopenharmony_ci			rbp = &(*rbp)->rb_right;
123662306a36Sopenharmony_ci		else
123762306a36Sopenharmony_ci			old_xattr = rb_entry(*rbp, struct simple_xattr, rb_node);
123862306a36Sopenharmony_ci		if (old_xattr)
123962306a36Sopenharmony_ci			break;
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	if (old_xattr) {
124362306a36Sopenharmony_ci		/* Fail if XATTR_CREATE is requested and the xattr exists. */
124462306a36Sopenharmony_ci		if (flags & XATTR_CREATE) {
124562306a36Sopenharmony_ci			err = -EEXIST;
124662306a36Sopenharmony_ci			goto out_unlock;
124762306a36Sopenharmony_ci		}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci		if (new_xattr)
125062306a36Sopenharmony_ci			rb_replace_node(&old_xattr->rb_node,
125162306a36Sopenharmony_ci					&new_xattr->rb_node, &xattrs->rb_root);
125262306a36Sopenharmony_ci		else
125362306a36Sopenharmony_ci			rb_erase(&old_xattr->rb_node, &xattrs->rb_root);
125462306a36Sopenharmony_ci	} else {
125562306a36Sopenharmony_ci		/* Fail if XATTR_REPLACE is requested but no xattr is found. */
125662306a36Sopenharmony_ci		if (flags & XATTR_REPLACE) {
125762306a36Sopenharmony_ci			err = -ENODATA;
125862306a36Sopenharmony_ci			goto out_unlock;
125962306a36Sopenharmony_ci		}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci		/*
126262306a36Sopenharmony_ci		 * If XATTR_CREATE or no flags are specified together with a
126362306a36Sopenharmony_ci		 * new value simply insert it.
126462306a36Sopenharmony_ci		 */
126562306a36Sopenharmony_ci		if (new_xattr) {
126662306a36Sopenharmony_ci			rb_link_node(&new_xattr->rb_node, parent, rbp);
126762306a36Sopenharmony_ci			rb_insert_color(&new_xattr->rb_node, &xattrs->rb_root);
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		/*
127162306a36Sopenharmony_ci		 * If XATTR_CREATE or no flags are specified and neither an
127262306a36Sopenharmony_ci		 * old or new xattr exist then we don't need to do anything.
127362306a36Sopenharmony_ci		 */
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ciout_unlock:
127762306a36Sopenharmony_ci	write_unlock(&xattrs->lock);
127862306a36Sopenharmony_ci	if (!err)
127962306a36Sopenharmony_ci		return old_xattr;
128062306a36Sopenharmony_ci	simple_xattr_free(new_xattr);
128162306a36Sopenharmony_ci	return ERR_PTR(err);
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic bool xattr_is_trusted(const char *name)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
128762306a36Sopenharmony_ci}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci/**
129062306a36Sopenharmony_ci * simple_xattr_list - list all xattr objects
129162306a36Sopenharmony_ci * @inode: inode from which to get the xattrs
129262306a36Sopenharmony_ci * @xattrs: the header of the xattr object
129362306a36Sopenharmony_ci * @buffer: the buffer to store all xattrs into
129462306a36Sopenharmony_ci * @size: the size of @buffer
129562306a36Sopenharmony_ci *
129662306a36Sopenharmony_ci * List all xattrs associated with @inode. If @buffer is NULL we returned
129762306a36Sopenharmony_ci * the required size of the buffer. If @buffer is provided we store the
129862306a36Sopenharmony_ci * xattrs value into it provided it is big enough.
129962306a36Sopenharmony_ci *
130062306a36Sopenharmony_ci * Note, the number of xattr names that can be listed with listxattr(2) is
130162306a36Sopenharmony_ci * limited to XATTR_LIST_MAX aka 65536 bytes. If a larger buffer is passed
130262306a36Sopenharmony_ci * then vfs_listxattr() caps it to XATTR_LIST_MAX and if more xattr names
130362306a36Sopenharmony_ci * are found it will return -E2BIG.
130462306a36Sopenharmony_ci *
130562306a36Sopenharmony_ci * Return: On success the required size or the size of the copied xattrs is
130662306a36Sopenharmony_ci * returned. On error a negative error code is returned.
130762306a36Sopenharmony_ci */
130862306a36Sopenharmony_cissize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
130962306a36Sopenharmony_ci			  char *buffer, size_t size)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	bool trusted = ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
131262306a36Sopenharmony_ci	struct simple_xattr *xattr;
131362306a36Sopenharmony_ci	struct rb_node *rbp;
131462306a36Sopenharmony_ci	ssize_t remaining_size = size;
131562306a36Sopenharmony_ci	int err = 0;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	err = posix_acl_listxattr(inode, &buffer, &remaining_size);
131862306a36Sopenharmony_ci	if (err)
131962306a36Sopenharmony_ci		return err;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	read_lock(&xattrs->lock);
132262306a36Sopenharmony_ci	for (rbp = rb_first(&xattrs->rb_root); rbp; rbp = rb_next(rbp)) {
132362306a36Sopenharmony_ci		xattr = rb_entry(rbp, struct simple_xattr, rb_node);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci		/* skip "trusted." attributes for unprivileged callers */
132662306a36Sopenharmony_ci		if (!trusted && xattr_is_trusted(xattr->name))
132762306a36Sopenharmony_ci			continue;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci		err = xattr_list_one(&buffer, &remaining_size, xattr->name);
133062306a36Sopenharmony_ci		if (err)
133162306a36Sopenharmony_ci			break;
133262306a36Sopenharmony_ci	}
133362306a36Sopenharmony_ci	read_unlock(&xattrs->lock);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	return err ? err : size - remaining_size;
133662306a36Sopenharmony_ci}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci/**
133962306a36Sopenharmony_ci * rbtree_simple_xattr_less - compare two xattr rbtree nodes
134062306a36Sopenharmony_ci * @new_node: new node
134162306a36Sopenharmony_ci * @node: current node
134262306a36Sopenharmony_ci *
134362306a36Sopenharmony_ci * Compare the xattr attached to @new_node with the xattr attached to @node.
134462306a36Sopenharmony_ci * Note that this function technically tolerates duplicate entries.
134562306a36Sopenharmony_ci *
134662306a36Sopenharmony_ci * Return: True if insertion point in the rbtree is found.
134762306a36Sopenharmony_ci */
134862306a36Sopenharmony_cistatic bool rbtree_simple_xattr_less(struct rb_node *new_node,
134962306a36Sopenharmony_ci				     const struct rb_node *node)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	return rbtree_simple_xattr_node_cmp(new_node, node) < 0;
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci/**
135562306a36Sopenharmony_ci * simple_xattr_add - add xattr objects
135662306a36Sopenharmony_ci * @xattrs: the header of the xattr object
135762306a36Sopenharmony_ci * @new_xattr: the xattr object to add
135862306a36Sopenharmony_ci *
135962306a36Sopenharmony_ci * Add an xattr object to @xattrs. This assumes no replacement or removal
136062306a36Sopenharmony_ci * of matching xattrs is wanted. Should only be called during inode
136162306a36Sopenharmony_ci * initialization when a few distinct initial xattrs are supposed to be set.
136262306a36Sopenharmony_ci */
136362306a36Sopenharmony_civoid simple_xattr_add(struct simple_xattrs *xattrs,
136462306a36Sopenharmony_ci		      struct simple_xattr *new_xattr)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	write_lock(&xattrs->lock);
136762306a36Sopenharmony_ci	rb_add(&new_xattr->rb_node, &xattrs->rb_root, rbtree_simple_xattr_less);
136862306a36Sopenharmony_ci	write_unlock(&xattrs->lock);
136962306a36Sopenharmony_ci}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci/**
137262306a36Sopenharmony_ci * simple_xattrs_init - initialize new xattr header
137362306a36Sopenharmony_ci * @xattrs: header to initialize
137462306a36Sopenharmony_ci *
137562306a36Sopenharmony_ci * Initialize relevant fields of a an xattr header.
137662306a36Sopenharmony_ci */
137762306a36Sopenharmony_civoid simple_xattrs_init(struct simple_xattrs *xattrs)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	xattrs->rb_root = RB_ROOT;
138062306a36Sopenharmony_ci	rwlock_init(&xattrs->lock);
138162306a36Sopenharmony_ci}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci/**
138462306a36Sopenharmony_ci * simple_xattrs_free - free xattrs
138562306a36Sopenharmony_ci * @xattrs: xattr header whose xattrs to destroy
138662306a36Sopenharmony_ci * @freed_space: approximate number of bytes of memory freed from @xattrs
138762306a36Sopenharmony_ci *
138862306a36Sopenharmony_ci * Destroy all xattrs in @xattr. When this is called no one can hold a
138962306a36Sopenharmony_ci * reference to any of the xattrs anymore.
139062306a36Sopenharmony_ci */
139162306a36Sopenharmony_civoid simple_xattrs_free(struct simple_xattrs *xattrs, size_t *freed_space)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	struct rb_node *rbp;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	if (freed_space)
139662306a36Sopenharmony_ci		*freed_space = 0;
139762306a36Sopenharmony_ci	rbp = rb_first(&xattrs->rb_root);
139862306a36Sopenharmony_ci	while (rbp) {
139962306a36Sopenharmony_ci		struct simple_xattr *xattr;
140062306a36Sopenharmony_ci		struct rb_node *rbp_next;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci		rbp_next = rb_next(rbp);
140362306a36Sopenharmony_ci		xattr = rb_entry(rbp, struct simple_xattr, rb_node);
140462306a36Sopenharmony_ci		rb_erase(&xattr->rb_node, &xattrs->rb_root);
140562306a36Sopenharmony_ci		if (freed_space)
140662306a36Sopenharmony_ci			*freed_space += simple_xattr_space(xattr->name,
140762306a36Sopenharmony_ci							   xattr->size);
140862306a36Sopenharmony_ci		simple_xattr_free(xattr);
140962306a36Sopenharmony_ci		rbp = rbp_next;
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci}
1412