10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0
2c59d87c4SChristoph Hellwig /*
3c59d87c4SChristoph Hellwig * Copyright (C) 2008 Christoph Hellwig.
4c59d87c4SChristoph Hellwig * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
5c59d87c4SChristoph Hellwig */
6c59d87c4SChristoph Hellwig
7c59d87c4SChristoph Hellwig #include "xfs.h"
85467b34bSDarrick J. Wong #include "xfs_shared.h"
9a4fbe6abSDave Chinner #include "xfs_format.h"
1069432832SDave Chinner #include "xfs_log_format.h"
1157062787SDave Chinner #include "xfs_da_format.h"
12383e32b0SDarrick J. Wong #include "xfs_trans_resv.h"
13383e32b0SDarrick J. Wong #include "xfs_mount.h"
14c59d87c4SChristoph Hellwig #include "xfs_inode.h"
15e0c41089SDave Chinner #include "xfs_da_btree.h"
16c59d87c4SChristoph Hellwig #include "xfs_attr.h"
175f213ddbSDarrick J. Wong #include "xfs_acl.h"
18d9c61ccbSDarrick J. Wong #include "xfs_log.h"
19d9c61ccbSDarrick J. Wong #include "xfs_xattr.h"
20c59d87c4SChristoph Hellwig
21c59d87c4SChristoph Hellwig #include <linux/posix_acl_xattr.h>
22c59d87c4SChristoph Hellwig
23d9c61ccbSDarrick J. Wong /*
24d9c61ccbSDarrick J. Wong * Get permission to use log-assisted atomic exchange of file extents.
25d9c61ccbSDarrick J. Wong *
26d9c61ccbSDarrick J. Wong * Callers must not be running any transactions or hold any inode locks, and
27d9c61ccbSDarrick J. Wong * they must release the permission by calling xlog_drop_incompat_feat
28d9c61ccbSDarrick J. Wong * when they're done.
29d9c61ccbSDarrick J. Wong */
30efc2efebSDarrick J. Wong static inline int
xfs_attr_grab_log_assist(struct xfs_mount * mp)31d9c61ccbSDarrick J. Wong xfs_attr_grab_log_assist(
32d9c61ccbSDarrick J. Wong struct xfs_mount *mp)
33d9c61ccbSDarrick J. Wong {
34d9c61ccbSDarrick J. Wong int error = 0;
35d9c61ccbSDarrick J. Wong
36d9c61ccbSDarrick J. Wong /*
37d9c61ccbSDarrick J. Wong * Protect ourselves from an idle log clearing the logged xattrs log
38d9c61ccbSDarrick J. Wong * incompat feature bit.
39d9c61ccbSDarrick J. Wong */
40d9c61ccbSDarrick J. Wong xlog_use_incompat_feat(mp->m_log);
41d9c61ccbSDarrick J. Wong
42d9c61ccbSDarrick J. Wong /*
43d9c61ccbSDarrick J. Wong * If log-assisted xattrs are already enabled, the caller can use the
44d9c61ccbSDarrick J. Wong * log assisted swap functions with the log-incompat reference we got.
45d9c61ccbSDarrick J. Wong */
46d9c61ccbSDarrick J. Wong if (xfs_sb_version_haslogxattrs(&mp->m_sb))
47d9c61ccbSDarrick J. Wong return 0;
48d9c61ccbSDarrick J. Wong
49*34389616SDarrick J. Wong /*
50*34389616SDarrick J. Wong * Check if the filesystem featureset is new enough to set this log
51*34389616SDarrick J. Wong * incompat feature bit. Strictly speaking, the minimum requirement is
52*34389616SDarrick J. Wong * a V5 filesystem for the superblock field, but we'll require rmap
53*34389616SDarrick J. Wong * or reflink to avoid having to deal with really old kernels.
54*34389616SDarrick J. Wong */
55*34389616SDarrick J. Wong if (!xfs_has_reflink(mp) && !xfs_has_rmapbt(mp)) {
56*34389616SDarrick J. Wong error = -EOPNOTSUPP;
57*34389616SDarrick J. Wong goto drop_incompat;
58*34389616SDarrick J. Wong }
59*34389616SDarrick J. Wong
60d9c61ccbSDarrick J. Wong /* Enable log-assisted xattrs. */
61d9c61ccbSDarrick J. Wong error = xfs_add_incompat_log_feature(mp,
62d9c61ccbSDarrick J. Wong XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
63d9c61ccbSDarrick J. Wong if (error)
64d9c61ccbSDarrick J. Wong goto drop_incompat;
65d9c61ccbSDarrick J. Wong
66d9c61ccbSDarrick J. Wong xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP,
67d9c61ccbSDarrick J. Wong "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!");
68d9c61ccbSDarrick J. Wong
69d9c61ccbSDarrick J. Wong return 0;
70d9c61ccbSDarrick J. Wong drop_incompat:
71d9c61ccbSDarrick J. Wong xlog_drop_incompat_feat(mp->m_log);
72d9c61ccbSDarrick J. Wong return error;
73d9c61ccbSDarrick J. Wong }
74d9c61ccbSDarrick J. Wong
75efc2efebSDarrick J. Wong static inline void
xfs_attr_rele_log_assist(struct xfs_mount * mp)76d9c61ccbSDarrick J. Wong xfs_attr_rele_log_assist(
77d9c61ccbSDarrick J. Wong struct xfs_mount *mp)
78d9c61ccbSDarrick J. Wong {
79d9c61ccbSDarrick J. Wong xlog_drop_incompat_feat(mp->m_log);
80d9c61ccbSDarrick J. Wong }
81c59d87c4SChristoph Hellwig
82f4288f01SDarrick J. Wong static inline bool
xfs_attr_want_log_assist(struct xfs_mount * mp)83f4288f01SDarrick J. Wong xfs_attr_want_log_assist(
84f4288f01SDarrick J. Wong struct xfs_mount *mp)
85f4288f01SDarrick J. Wong {
86f4288f01SDarrick J. Wong #ifdef DEBUG
87f4288f01SDarrick J. Wong /* Logged xattrs require a V5 super for log_incompat */
88f4288f01SDarrick J. Wong return xfs_has_crc(mp) && xfs_globals.larp;
89f4288f01SDarrick J. Wong #else
90f4288f01SDarrick J. Wong return false;
91f4288f01SDarrick J. Wong #endif
92f4288f01SDarrick J. Wong }
93f4288f01SDarrick J. Wong
94efc2efebSDarrick J. Wong /*
95efc2efebSDarrick J. Wong * Set or remove an xattr, having grabbed the appropriate logging resources
96efc2efebSDarrick J. Wong * prior to calling libxfs.
97efc2efebSDarrick J. Wong */
98efc2efebSDarrick J. Wong int
xfs_attr_change(struct xfs_da_args * args)99efc2efebSDarrick J. Wong xfs_attr_change(
100efc2efebSDarrick J. Wong struct xfs_da_args *args)
101efc2efebSDarrick J. Wong {
102efc2efebSDarrick J. Wong struct xfs_mount *mp = args->dp->i_mount;
103efc2efebSDarrick J. Wong bool use_logging = false;
104efc2efebSDarrick J. Wong int error;
105efc2efebSDarrick J. Wong
106f4288f01SDarrick J. Wong ASSERT(!(args->op_flags & XFS_DA_OP_LOGGED));
107f4288f01SDarrick J. Wong
108f4288f01SDarrick J. Wong if (xfs_attr_want_log_assist(mp)) {
109efc2efebSDarrick J. Wong error = xfs_attr_grab_log_assist(mp);
110efc2efebSDarrick J. Wong if (error)
111efc2efebSDarrick J. Wong return error;
112efc2efebSDarrick J. Wong
113f4288f01SDarrick J. Wong args->op_flags |= XFS_DA_OP_LOGGED;
114efc2efebSDarrick J. Wong use_logging = true;
115efc2efebSDarrick J. Wong }
116efc2efebSDarrick J. Wong
117efc2efebSDarrick J. Wong error = xfs_attr_set(args);
118efc2efebSDarrick J. Wong
119efc2efebSDarrick J. Wong if (use_logging)
120efc2efebSDarrick J. Wong xfs_attr_rele_log_assist(mp);
121efc2efebSDarrick J. Wong return error;
122efc2efebSDarrick J. Wong }
123efc2efebSDarrick J. Wong
124efc2efebSDarrick J. Wong
125c59d87c4SChristoph Hellwig static int
xfs_xattr_get(const struct xattr_handler * handler,struct dentry * unused,struct inode * inode,const char * name,void * value,size_t size)126b296821aSAl Viro xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
127b296821aSAl Viro struct inode *inode, const char *name, void *value, size_t size)
128c59d87c4SChristoph Hellwig {
129e5171d7eSChristoph Hellwig struct xfs_da_args args = {
130e5171d7eSChristoph Hellwig .dp = XFS_I(inode),
131d5f0f49aSChristoph Hellwig .attr_filter = handler->flags,
132e5171d7eSChristoph Hellwig .name = name,
133e5171d7eSChristoph Hellwig .namelen = strlen(name),
134e5171d7eSChristoph Hellwig .value = value,
135e5171d7eSChristoph Hellwig .valuelen = size,
136e5171d7eSChristoph Hellwig };
137e5171d7eSChristoph Hellwig int error;
138c59d87c4SChristoph Hellwig
139e5171d7eSChristoph Hellwig error = xfs_attr_get(&args);
140c59d87c4SChristoph Hellwig if (error)
141c59d87c4SChristoph Hellwig return error;
142e5171d7eSChristoph Hellwig return args.valuelen;
143c59d87c4SChristoph Hellwig }
144c59d87c4SChristoph Hellwig
145c59d87c4SChristoph Hellwig static int
xfs_xattr_set(const struct xattr_handler * handler,struct mnt_idmap * idmap,struct dentry * unused,struct inode * inode,const char * name,const void * value,size_t size,int flags)146e65ce2a5SChristian Brauner xfs_xattr_set(const struct xattr_handler *handler,
14739f60c1cSChristian Brauner struct mnt_idmap *idmap, struct dentry *unused,
14859301226SAl Viro struct inode *inode, const char *name, const void *value,
14959301226SAl Viro size_t size, int flags)
150c59d87c4SChristoph Hellwig {
151a2544622SChristoph Hellwig struct xfs_da_args args = {
152a2544622SChristoph Hellwig .dp = XFS_I(inode),
153d5f0f49aSChristoph Hellwig .attr_filter = handler->flags,
154d5f0f49aSChristoph Hellwig .attr_flags = flags,
155a2544622SChristoph Hellwig .name = name,
156a2544622SChristoph Hellwig .namelen = strlen(name),
157a2544622SChristoph Hellwig .value = (void *)value,
158a2544622SChristoph Hellwig .valuelen = size,
159a2544622SChristoph Hellwig };
16067d8e04eSBrian Foster int error;
161c59d87c4SChristoph Hellwig
162efc2efebSDarrick J. Wong error = xfs_attr_change(&args);
163d5f0f49aSChristoph Hellwig if (!error && (handler->flags & XFS_ATTR_ROOT))
1645a3930e2SChristoph Hellwig xfs_forget_acl(inode, name);
16567d8e04eSBrian Foster return error;
166c59d87c4SChristoph Hellwig }
167c59d87c4SChristoph Hellwig
168c59d87c4SChristoph Hellwig static const struct xattr_handler xfs_xattr_user_handler = {
169c59d87c4SChristoph Hellwig .prefix = XATTR_USER_PREFIX,
170c59d87c4SChristoph Hellwig .flags = 0, /* no flags implies user namespace */
171c59d87c4SChristoph Hellwig .get = xfs_xattr_get,
172c59d87c4SChristoph Hellwig .set = xfs_xattr_set,
173c59d87c4SChristoph Hellwig };
174c59d87c4SChristoph Hellwig
175c59d87c4SChristoph Hellwig static const struct xattr_handler xfs_xattr_trusted_handler = {
176c59d87c4SChristoph Hellwig .prefix = XATTR_TRUSTED_PREFIX,
177d5f0f49aSChristoph Hellwig .flags = XFS_ATTR_ROOT,
178c59d87c4SChristoph Hellwig .get = xfs_xattr_get,
179c59d87c4SChristoph Hellwig .set = xfs_xattr_set,
180c59d87c4SChristoph Hellwig };
181c59d87c4SChristoph Hellwig
182c59d87c4SChristoph Hellwig static const struct xattr_handler xfs_xattr_security_handler = {
183c59d87c4SChristoph Hellwig .prefix = XATTR_SECURITY_PREFIX,
184d5f0f49aSChristoph Hellwig .flags = XFS_ATTR_SECURE,
185c59d87c4SChristoph Hellwig .get = xfs_xattr_get,
186c59d87c4SChristoph Hellwig .set = xfs_xattr_set,
187c59d87c4SChristoph Hellwig };
188c59d87c4SChristoph Hellwig
189c59d87c4SChristoph Hellwig const struct xattr_handler *xfs_xattr_handlers[] = {
190c59d87c4SChristoph Hellwig &xfs_xattr_user_handler,
191c59d87c4SChristoph Hellwig &xfs_xattr_trusted_handler,
192c59d87c4SChristoph Hellwig &xfs_xattr_security_handler,
193c59d87c4SChristoph Hellwig NULL
194c59d87c4SChristoph Hellwig };
195c59d87c4SChristoph Hellwig
196f7a136aeSEric Sandeen static void
__xfs_xattr_put_listent(struct xfs_attr_list_context * context,char * prefix,int prefix_len,unsigned char * name,int namelen)1975d92b75cSAndreas Gruenbacher __xfs_xattr_put_listent(
1985d92b75cSAndreas Gruenbacher struct xfs_attr_list_context *context,
1995d92b75cSAndreas Gruenbacher char *prefix,
2005d92b75cSAndreas Gruenbacher int prefix_len,
2015d92b75cSAndreas Gruenbacher unsigned char *name,
2025d92b75cSAndreas Gruenbacher int namelen)
203c59d87c4SChristoph Hellwig {
2045d92b75cSAndreas Gruenbacher char *offset;
2055d92b75cSAndreas Gruenbacher int arraytop;
206c59d87c4SChristoph Hellwig
2073b50086fSDarrick J. Wong if (context->count < 0 || context->seen_enough)
2083b50086fSDarrick J. Wong return;
2093b50086fSDarrick J. Wong
210a9c8c69bSChristoph Hellwig if (!context->buffer)
2115d92b75cSAndreas Gruenbacher goto compute_size;
2125d92b75cSAndreas Gruenbacher
2135d92b75cSAndreas Gruenbacher arraytop = context->count + prefix_len + namelen + 1;
2145d92b75cSAndreas Gruenbacher if (arraytop > context->firstu) {
2155d92b75cSAndreas Gruenbacher context->count = -1; /* insufficient space */
216791cc43bSArtem Savkov context->seen_enough = 1;
217f7a136aeSEric Sandeen return;
2185d92b75cSAndreas Gruenbacher }
219a9c8c69bSChristoph Hellwig offset = context->buffer + context->count;
220fd5beaffSDarrick J. Wong memcpy(offset, prefix, prefix_len);
2215d92b75cSAndreas Gruenbacher offset += prefix_len;
2225d92b75cSAndreas Gruenbacher strncpy(offset, (char *)name, namelen); /* real name */
2235d92b75cSAndreas Gruenbacher offset += namelen;
2245d92b75cSAndreas Gruenbacher *offset = '\0';
2255d92b75cSAndreas Gruenbacher
2265d92b75cSAndreas Gruenbacher compute_size:
2275d92b75cSAndreas Gruenbacher context->count += prefix_len + namelen + 1;
228f7a136aeSEric Sandeen return;
229c59d87c4SChristoph Hellwig }
230c59d87c4SChristoph Hellwig
231f7a136aeSEric Sandeen static void
xfs_xattr_put_listent(struct xfs_attr_list_context * context,int flags,unsigned char * name,int namelen,int valuelen)232c59d87c4SChristoph Hellwig xfs_xattr_put_listent(
233c59d87c4SChristoph Hellwig struct xfs_attr_list_context *context,
234c59d87c4SChristoph Hellwig int flags,
235c59d87c4SChristoph Hellwig unsigned char *name,
236c59d87c4SChristoph Hellwig int namelen,
237e5bd12bfSEric Sandeen int valuelen)
238c59d87c4SChristoph Hellwig {
2395d92b75cSAndreas Gruenbacher char *prefix;
2405d92b75cSAndreas Gruenbacher int prefix_len;
241c59d87c4SChristoph Hellwig
242c59d87c4SChristoph Hellwig ASSERT(context->count >= 0);
243c59d87c4SChristoph Hellwig
2445d92b75cSAndreas Gruenbacher if (flags & XFS_ATTR_ROOT) {
2455d92b75cSAndreas Gruenbacher #ifdef CONFIG_XFS_POSIX_ACL
2465d92b75cSAndreas Gruenbacher if (namelen == SGI_ACL_FILE_SIZE &&
2475d92b75cSAndreas Gruenbacher strncmp(name, SGI_ACL_FILE,
2485d92b75cSAndreas Gruenbacher SGI_ACL_FILE_SIZE) == 0) {
249f7a136aeSEric Sandeen __xfs_xattr_put_listent(
2505d92b75cSAndreas Gruenbacher context, XATTR_SYSTEM_PREFIX,
2515d92b75cSAndreas Gruenbacher XATTR_SYSTEM_PREFIX_LEN,
2525d92b75cSAndreas Gruenbacher XATTR_POSIX_ACL_ACCESS,
2535d92b75cSAndreas Gruenbacher strlen(XATTR_POSIX_ACL_ACCESS));
2545d92b75cSAndreas Gruenbacher } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
2555d92b75cSAndreas Gruenbacher strncmp(name, SGI_ACL_DEFAULT,
2565d92b75cSAndreas Gruenbacher SGI_ACL_DEFAULT_SIZE) == 0) {
257f7a136aeSEric Sandeen __xfs_xattr_put_listent(
2585d92b75cSAndreas Gruenbacher context, XATTR_SYSTEM_PREFIX,
2595d92b75cSAndreas Gruenbacher XATTR_SYSTEM_PREFIX_LEN,
2605d92b75cSAndreas Gruenbacher XATTR_POSIX_ACL_DEFAULT,
2615d92b75cSAndreas Gruenbacher strlen(XATTR_POSIX_ACL_DEFAULT));
2625d92b75cSAndreas Gruenbacher }
2635d92b75cSAndreas Gruenbacher #endif
2645d92b75cSAndreas Gruenbacher
265c59d87c4SChristoph Hellwig /*
266c59d87c4SChristoph Hellwig * Only show root namespace entries if we are actually allowed to
267c59d87c4SChristoph Hellwig * see them.
268c59d87c4SChristoph Hellwig */
2695d92b75cSAndreas Gruenbacher if (!capable(CAP_SYS_ADMIN))
270f7a136aeSEric Sandeen return;
271c59d87c4SChristoph Hellwig
2725d92b75cSAndreas Gruenbacher prefix = XATTR_TRUSTED_PREFIX;
2735d92b75cSAndreas Gruenbacher prefix_len = XATTR_TRUSTED_PREFIX_LEN;
2745d92b75cSAndreas Gruenbacher } else if (flags & XFS_ATTR_SECURE) {
2755d92b75cSAndreas Gruenbacher prefix = XATTR_SECURITY_PREFIX;
2765d92b75cSAndreas Gruenbacher prefix_len = XATTR_SECURITY_PREFIX_LEN;
2775d92b75cSAndreas Gruenbacher } else {
2785d92b75cSAndreas Gruenbacher prefix = XATTR_USER_PREFIX;
2795d92b75cSAndreas Gruenbacher prefix_len = XATTR_USER_PREFIX_LEN;
280c59d87c4SChristoph Hellwig }
281c59d87c4SChristoph Hellwig
282f7a136aeSEric Sandeen __xfs_xattr_put_listent(context, prefix, prefix_len, name,
2835d92b75cSAndreas Gruenbacher namelen);
284f7a136aeSEric Sandeen return;
285c59d87c4SChristoph Hellwig }
286c59d87c4SChristoph Hellwig
287c59d87c4SChristoph Hellwig ssize_t
xfs_vn_listxattr(struct dentry * dentry,char * data,size_t size)2882a6fba6dSEric Sandeen xfs_vn_listxattr(
2892a6fba6dSEric Sandeen struct dentry *dentry,
2902a6fba6dSEric Sandeen char *data,
2912a6fba6dSEric Sandeen size_t size)
292c59d87c4SChristoph Hellwig {
293c59d87c4SChristoph Hellwig struct xfs_attr_list_context context;
2942b0143b5SDavid Howells struct inode *inode = d_inode(dentry);
2952a6fba6dSEric Sandeen int error;
296c59d87c4SChristoph Hellwig
297c59d87c4SChristoph Hellwig /*
298c59d87c4SChristoph Hellwig * First read the regular on-disk attributes.
299c59d87c4SChristoph Hellwig */
300c59d87c4SChristoph Hellwig memset(&context, 0, sizeof(context));
301c59d87c4SChristoph Hellwig context.dp = XFS_I(inode);
302c59d87c4SChristoph Hellwig context.resynch = 1;
303a9c8c69bSChristoph Hellwig context.buffer = size ? data : NULL;
304c59d87c4SChristoph Hellwig context.bufsize = size;
305c59d87c4SChristoph Hellwig context.firstu = context.bufsize;
306c59d87c4SChristoph Hellwig context.put_listent = xfs_xattr_put_listent;
307c59d87c4SChristoph Hellwig
30817e1dd83SChristoph Hellwig error = xfs_attr_list(&context);
3092a6fba6dSEric Sandeen if (error)
3102a6fba6dSEric Sandeen return error;
311c59d87c4SChristoph Hellwig if (context.count < 0)
312c59d87c4SChristoph Hellwig return -ERANGE;
313c59d87c4SChristoph Hellwig
314c59d87c4SChristoph Hellwig return context.count;
315c59d87c4SChristoph Hellwig }
316