1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2008 Christoph Hellwig.
4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
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"
19 #include "xfs_xattr.h"
20 #include "xfs_quota.h"
22 #include <linux/posix_acl_xattr.h>
25 * Get permission to use log-assisted atomic exchange of file extents.
26 * Callers must not be running any transactions or hold any ILOCKs.
29 xfs_attr_grab_log_assist(
34 /* xattr update log intent items are already enabled */
35 if (xfs_is_using_logged_xattrs(mp))
39 * Check if the filesystem featureset is new enough to set this log
40 * incompat feature bit. Strictly speaking, the minimum requirement is
41 * a V5 filesystem for the superblock field, but we'll require rmap
42 * or reflink to avoid having to deal with really old kernels.
44 if (!xfs_has_reflink(mp) && !xfs_has_rmapbt(mp))
47 /* Enable log-assisted xattrs. */
48 error = xfs_add_incompat_log_feature(mp,
49 XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
52 xfs_set_using_logged_xattrs(mp);
54 xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP,
55 "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!");
61 xfs_attr_want_log_assist(
65 /* Logged xattrs require a V5 super for log_incompat */
66 return xfs_has_crc(mp) && xfs_globals.larp;
73 * Set or remove an xattr, having grabbed the appropriate logging resources
74 * prior to calling libxfs. Callers of this function are only required to
75 * initialize the inode, attr_filter, name, namelen, value, and valuelen fields
80 struct xfs_da_args *args,
81 enum xfs_attr_update op)
83 struct xfs_mount *mp = args->dp->i_mount;
86 if (xfs_is_shutdown(mp))
89 error = xfs_qm_dqattach(args->dp);
94 * We have no control over the attribute names that userspace passes us
95 * to remove, so we have to allow the name lookup prior to attribute
96 * removal to fail as well.
98 args->op_flags = XFS_DA_OP_OKNOENT;
100 if (xfs_attr_want_log_assist(mp)) {
101 error = xfs_attr_grab_log_assist(mp);
105 args->op_flags |= XFS_DA_OP_LOGGED;
108 args->owner = args->dp->i_ino;
109 args->geo = mp->m_attr_geo;
110 args->whichfork = XFS_ATTR_FORK;
111 xfs_attr_sethash(args);
113 return xfs_attr_set(args, op, args->attr_filter & XFS_ATTR_ROOT);
118 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
119 struct inode *inode, const char *name, void *value, size_t size)
121 struct xfs_da_args args = {
123 .attr_filter = handler->flags,
125 .namelen = strlen(name),
131 if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))
134 error = xfs_attr_get(&args);
137 return args.valuelen;
140 static inline enum xfs_attr_update
141 xfs_xattr_flags_to_op(
146 return XFS_ATTRUPDATE_REMOVE;
147 if (flags & XATTR_CREATE)
148 return XFS_ATTRUPDATE_CREATE;
149 if (flags & XATTR_REPLACE)
150 return XFS_ATTRUPDATE_REPLACE;
151 return XFS_ATTRUPDATE_UPSERT;
155 xfs_xattr_set(const struct xattr_handler *handler,
156 struct mnt_idmap *idmap, struct dentry *unused,
157 struct inode *inode, const char *name, const void *value,
158 size_t size, int flags)
160 struct xfs_da_args args = {
162 .attr_filter = handler->flags,
164 .namelen = strlen(name),
165 .value = (void *)value,
170 error = xfs_attr_change(&args, xfs_xattr_flags_to_op(flags, value));
171 if (!error && (handler->flags & XFS_ATTR_ROOT))
172 xfs_forget_acl(inode, name);
176 static const struct xattr_handler xfs_xattr_user_handler = {
177 .prefix = XATTR_USER_PREFIX,
178 .flags = 0, /* no flags implies user namespace */
179 .get = xfs_xattr_get,
180 .set = xfs_xattr_set,
183 static const struct xattr_handler xfs_xattr_trusted_handler = {
184 .prefix = XATTR_TRUSTED_PREFIX,
185 .flags = XFS_ATTR_ROOT,
186 .get = xfs_xattr_get,
187 .set = xfs_xattr_set,
190 static const struct xattr_handler xfs_xattr_security_handler = {
191 .prefix = XATTR_SECURITY_PREFIX,
192 .flags = XFS_ATTR_SECURE,
193 .get = xfs_xattr_get,
194 .set = xfs_xattr_set,
197 const struct xattr_handler * const xfs_xattr_handlers[] = {
198 &xfs_xattr_user_handler,
199 &xfs_xattr_trusted_handler,
200 &xfs_xattr_security_handler,
205 __xfs_xattr_put_listent(
206 struct xfs_attr_list_context *context,
215 if (context->count < 0 || context->seen_enough)
218 if (!context->buffer)
221 arraytop = context->count + prefix_len + namelen + 1;
222 if (arraytop > context->firstu) {
223 context->count = -1; /* insufficient space */
224 context->seen_enough = 1;
227 offset = context->buffer + context->count;
228 memcpy(offset, prefix, prefix_len);
229 offset += prefix_len;
230 strncpy(offset, (char *)name, namelen); /* real name */
235 context->count += prefix_len + namelen + 1;
240 xfs_xattr_put_listent(
241 struct xfs_attr_list_context *context,
251 ASSERT(context->count >= 0);
253 /* Don't expose private xattr namespaces. */
254 if (flags & XFS_ATTR_PRIVATE_NSP_MASK)
257 if (flags & XFS_ATTR_ROOT) {
258 #ifdef CONFIG_XFS_POSIX_ACL
259 if (namelen == SGI_ACL_FILE_SIZE &&
260 strncmp(name, SGI_ACL_FILE,
261 SGI_ACL_FILE_SIZE) == 0) {
262 __xfs_xattr_put_listent(
263 context, XATTR_SYSTEM_PREFIX,
264 XATTR_SYSTEM_PREFIX_LEN,
265 XATTR_POSIX_ACL_ACCESS,
266 strlen(XATTR_POSIX_ACL_ACCESS));
267 } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
268 strncmp(name, SGI_ACL_DEFAULT,
269 SGI_ACL_DEFAULT_SIZE) == 0) {
270 __xfs_xattr_put_listent(
271 context, XATTR_SYSTEM_PREFIX,
272 XATTR_SYSTEM_PREFIX_LEN,
273 XATTR_POSIX_ACL_DEFAULT,
274 strlen(XATTR_POSIX_ACL_DEFAULT));
279 * Only show root namespace entries if we are actually allowed to
282 if (!capable(CAP_SYS_ADMIN))
285 prefix = XATTR_TRUSTED_PREFIX;
286 prefix_len = XATTR_TRUSTED_PREFIX_LEN;
287 } else if (flags & XFS_ATTR_SECURE) {
288 prefix = XATTR_SECURITY_PREFIX;
289 prefix_len = XATTR_SECURITY_PREFIX_LEN;
291 prefix = XATTR_USER_PREFIX;
292 prefix_len = XATTR_USER_PREFIX_LEN;
295 __xfs_xattr_put_listent(context, prefix, prefix_len, name,
302 struct dentry *dentry,
306 struct xfs_attr_list_context context;
307 struct inode *inode = d_inode(dentry);
310 if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))
314 * First read the regular on-disk attributes.
316 memset(&context, 0, sizeof(context));
317 context.dp = XFS_I(inode);
319 context.buffer = size ? data : NULL;
320 context.bufsize = size;
321 context.firstu = context.bufsize;
322 context.put_listent = xfs_xattr_put_listent;
324 error = xfs_attr_list(&context);
327 if (context.count < 0)
330 return context.count;