cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xfs_xattr.c (6868B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2008 Christoph Hellwig.
      4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
      5 */
      6
      7#include "xfs.h"
      8#include "xfs_shared.h"
      9#include "xfs_format.h"
     10#include "xfs_log_format.h"
     11#include "xfs_da_format.h"
     12#include "xfs_trans_resv.h"
     13#include "xfs_mount.h"
     14#include "xfs_inode.h"
     15#include "xfs_da_btree.h"
     16#include "xfs_attr.h"
     17#include "xfs_acl.h"
     18#include "xfs_log.h"
     19#include "xfs_xattr.h"
     20
     21#include <linux/posix_acl_xattr.h>
     22
     23/*
     24 * Get permission to use log-assisted atomic exchange of file extents.
     25 *
     26 * Callers must not be running any transactions or hold any inode locks, and
     27 * they must release the permission by calling xlog_drop_incompat_feat
     28 * when they're done.
     29 */
     30static inline int
     31xfs_attr_grab_log_assist(
     32	struct xfs_mount	*mp)
     33{
     34	int			error = 0;
     35
     36	/*
     37	 * Protect ourselves from an idle log clearing the logged xattrs log
     38	 * incompat feature bit.
     39	 */
     40	xlog_use_incompat_feat(mp->m_log);
     41
     42	/*
     43	 * If log-assisted xattrs are already enabled, the caller can use the
     44	 * log assisted swap functions with the log-incompat reference we got.
     45	 */
     46	if (xfs_sb_version_haslogxattrs(&mp->m_sb))
     47		return 0;
     48
     49	/* Enable log-assisted xattrs. */
     50	error = xfs_add_incompat_log_feature(mp,
     51			XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
     52	if (error)
     53		goto drop_incompat;
     54
     55	xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP,
     56 "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!");
     57
     58	return 0;
     59drop_incompat:
     60	xlog_drop_incompat_feat(mp->m_log);
     61	return error;
     62}
     63
     64static inline void
     65xfs_attr_rele_log_assist(
     66	struct xfs_mount	*mp)
     67{
     68	xlog_drop_incompat_feat(mp->m_log);
     69}
     70
     71static inline bool
     72xfs_attr_want_log_assist(
     73	struct xfs_mount	*mp)
     74{
     75#ifdef DEBUG
     76	/* Logged xattrs require a V5 super for log_incompat */
     77	return xfs_has_crc(mp) && xfs_globals.larp;
     78#else
     79	return false;
     80#endif
     81}
     82
     83/*
     84 * Set or remove an xattr, having grabbed the appropriate logging resources
     85 * prior to calling libxfs.
     86 */
     87int
     88xfs_attr_change(
     89	struct xfs_da_args	*args)
     90{
     91	struct xfs_mount	*mp = args->dp->i_mount;
     92	bool			use_logging = false;
     93	int			error;
     94
     95	ASSERT(!(args->op_flags & XFS_DA_OP_LOGGED));
     96
     97	if (xfs_attr_want_log_assist(mp)) {
     98		error = xfs_attr_grab_log_assist(mp);
     99		if (error)
    100			return error;
    101
    102		args->op_flags |= XFS_DA_OP_LOGGED;
    103		use_logging = true;
    104	}
    105
    106	error = xfs_attr_set(args);
    107
    108	if (use_logging)
    109		xfs_attr_rele_log_assist(mp);
    110	return error;
    111}
    112
    113
    114static int
    115xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
    116		struct inode *inode, const char *name, void *value, size_t size)
    117{
    118	struct xfs_da_args	args = {
    119		.dp		= XFS_I(inode),
    120		.attr_filter	= handler->flags,
    121		.name		= name,
    122		.namelen	= strlen(name),
    123		.value		= value,
    124		.valuelen	= size,
    125	};
    126	int			error;
    127
    128	error = xfs_attr_get(&args);
    129	if (error)
    130		return error;
    131	return args.valuelen;
    132}
    133
    134static int
    135xfs_xattr_set(const struct xattr_handler *handler,
    136	      struct user_namespace *mnt_userns, struct dentry *unused,
    137	      struct inode *inode, const char *name, const void *value,
    138	      size_t size, int flags)
    139{
    140	struct xfs_da_args	args = {
    141		.dp		= XFS_I(inode),
    142		.attr_filter	= handler->flags,
    143		.attr_flags	= flags,
    144		.name		= name,
    145		.namelen	= strlen(name),
    146		.value		= (void *)value,
    147		.valuelen	= size,
    148	};
    149	int			error;
    150
    151	error = xfs_attr_change(&args);
    152	if (!error && (handler->flags & XFS_ATTR_ROOT))
    153		xfs_forget_acl(inode, name);
    154	return error;
    155}
    156
    157static const struct xattr_handler xfs_xattr_user_handler = {
    158	.prefix	= XATTR_USER_PREFIX,
    159	.flags	= 0, /* no flags implies user namespace */
    160	.get	= xfs_xattr_get,
    161	.set	= xfs_xattr_set,
    162};
    163
    164static const struct xattr_handler xfs_xattr_trusted_handler = {
    165	.prefix	= XATTR_TRUSTED_PREFIX,
    166	.flags	= XFS_ATTR_ROOT,
    167	.get	= xfs_xattr_get,
    168	.set	= xfs_xattr_set,
    169};
    170
    171static const struct xattr_handler xfs_xattr_security_handler = {
    172	.prefix	= XATTR_SECURITY_PREFIX,
    173	.flags	= XFS_ATTR_SECURE,
    174	.get	= xfs_xattr_get,
    175	.set	= xfs_xattr_set,
    176};
    177
    178const struct xattr_handler *xfs_xattr_handlers[] = {
    179	&xfs_xattr_user_handler,
    180	&xfs_xattr_trusted_handler,
    181	&xfs_xattr_security_handler,
    182#ifdef CONFIG_XFS_POSIX_ACL
    183	&posix_acl_access_xattr_handler,
    184	&posix_acl_default_xattr_handler,
    185#endif
    186	NULL
    187};
    188
    189static void
    190__xfs_xattr_put_listent(
    191	struct xfs_attr_list_context *context,
    192	char *prefix,
    193	int prefix_len,
    194	unsigned char *name,
    195	int namelen)
    196{
    197	char *offset;
    198	int arraytop;
    199
    200	if (context->count < 0 || context->seen_enough)
    201		return;
    202
    203	if (!context->buffer)
    204		goto compute_size;
    205
    206	arraytop = context->count + prefix_len + namelen + 1;
    207	if (arraytop > context->firstu) {
    208		context->count = -1;	/* insufficient space */
    209		context->seen_enough = 1;
    210		return;
    211	}
    212	offset = context->buffer + context->count;
    213	strncpy(offset, prefix, prefix_len);
    214	offset += prefix_len;
    215	strncpy(offset, (char *)name, namelen);			/* real name */
    216	offset += namelen;
    217	*offset = '\0';
    218
    219compute_size:
    220	context->count += prefix_len + namelen + 1;
    221	return;
    222}
    223
    224static void
    225xfs_xattr_put_listent(
    226	struct xfs_attr_list_context *context,
    227	int		flags,
    228	unsigned char	*name,
    229	int		namelen,
    230	int		valuelen)
    231{
    232	char *prefix;
    233	int prefix_len;
    234
    235	ASSERT(context->count >= 0);
    236
    237	if (flags & XFS_ATTR_ROOT) {
    238#ifdef CONFIG_XFS_POSIX_ACL
    239		if (namelen == SGI_ACL_FILE_SIZE &&
    240		    strncmp(name, SGI_ACL_FILE,
    241			    SGI_ACL_FILE_SIZE) == 0) {
    242			__xfs_xattr_put_listent(
    243					context, XATTR_SYSTEM_PREFIX,
    244					XATTR_SYSTEM_PREFIX_LEN,
    245					XATTR_POSIX_ACL_ACCESS,
    246					strlen(XATTR_POSIX_ACL_ACCESS));
    247		} else if (namelen == SGI_ACL_DEFAULT_SIZE &&
    248			 strncmp(name, SGI_ACL_DEFAULT,
    249				 SGI_ACL_DEFAULT_SIZE) == 0) {
    250			__xfs_xattr_put_listent(
    251					context, XATTR_SYSTEM_PREFIX,
    252					XATTR_SYSTEM_PREFIX_LEN,
    253					XATTR_POSIX_ACL_DEFAULT,
    254					strlen(XATTR_POSIX_ACL_DEFAULT));
    255		}
    256#endif
    257
    258		/*
    259		 * Only show root namespace entries if we are actually allowed to
    260		 * see them.
    261		 */
    262		if (!capable(CAP_SYS_ADMIN))
    263			return;
    264
    265		prefix = XATTR_TRUSTED_PREFIX;
    266		prefix_len = XATTR_TRUSTED_PREFIX_LEN;
    267	} else if (flags & XFS_ATTR_SECURE) {
    268		prefix = XATTR_SECURITY_PREFIX;
    269		prefix_len = XATTR_SECURITY_PREFIX_LEN;
    270	} else {
    271		prefix = XATTR_USER_PREFIX;
    272		prefix_len = XATTR_USER_PREFIX_LEN;
    273	}
    274
    275	__xfs_xattr_put_listent(context, prefix, prefix_len, name,
    276				namelen);
    277	return;
    278}
    279
    280ssize_t
    281xfs_vn_listxattr(
    282	struct dentry	*dentry,
    283	char		*data,
    284	size_t		size)
    285{
    286	struct xfs_attr_list_context context;
    287	struct inode	*inode = d_inode(dentry);
    288	int		error;
    289
    290	/*
    291	 * First read the regular on-disk attributes.
    292	 */
    293	memset(&context, 0, sizeof(context));
    294	context.dp = XFS_I(inode);
    295	context.resynch = 1;
    296	context.buffer = size ? data : NULL;
    297	context.bufsize = size;
    298	context.firstu = context.bufsize;
    299	context.put_listent = xfs_xattr_put_listent;
    300
    301	error = xfs_attr_list(&context);
    302	if (error)
    303		return error;
    304	if (context.count < 0)
    305		return -ERANGE;
    306
    307	return context.count;
    308}