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