blob: 7b9a0ed1b11f74b7870e0e52e4ad2fafad0feaf4 [file] [log] [blame]
Dave Chinner0b61f8a2018-06-05 19:42:14 -07001// SPDX-License-Identifier: GPL-2.0
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +10002/*
3 * Copyright (C) 2008 Christoph Hellwig.
4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +10005 */
6
7#include "xfs.h"
Darrick J. Wong5467b342019-06-28 19:25:35 -07008#include "xfs_shared.h"
Dave Chinnera4fbe6a2013-10-23 10:51:50 +11009#include "xfs_format.h"
Dave Chinner69432832013-08-12 20:49:23 +100010#include "xfs_log_format.h"
Dave Chinner57062782013-10-15 09:17:51 +110011#include "xfs_da_format.h"
Darrick J. Wong383e32b2021-03-22 09:51:54 -070012#include "xfs_trans_resv.h"
13#include "xfs_mount.h"
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100014#include "xfs_inode.h"
Dave Chinnere0c41082022-05-12 15:12:52 +100015#include "xfs_da_btree.h"
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100016#include "xfs_attr.h"
Darrick J. Wong5f213dd2019-11-06 17:19:33 -080017#include "xfs_acl.h"
Darrick J. Wongd9c61cc2022-05-27 10:33:29 +100018#include "xfs_log.h"
19#include "xfs_xattr.h"
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100020
21#include <linux/posix_acl_xattr.h>
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100022
Darrick J. Wongd9c61cc2022-05-27 10:33:29 +100023/*
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 */
Darrick J. Wongefc2efe2022-05-27 10:34:04 +100030static inline int
Darrick J. Wongd9c61cc2022-05-27 10:33:29 +100031xfs_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
Darrick J. Wongefc2efe2022-05-27 10:34:04 +100064static inline void
Darrick J. Wongd9c61cc2022-05-27 10:33:29 +100065xfs_attr_rele_log_assist(
66 struct xfs_mount *mp)
67{
68 xlog_drop_incompat_feat(mp->m_log);
69}
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100070
Darrick J. Wongf4288f02022-06-05 18:51:22 -070071static 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
Darrick J. Wongefc2efe2022-05-27 10:34:04 +100083/*
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
Darrick J. Wongf4288f02022-06-05 18:51:22 -070095 ASSERT(!(args->op_flags & XFS_DA_OP_LOGGED));
96
97 if (xfs_attr_want_log_assist(mp)) {
Darrick J. Wongefc2efe2022-05-27 10:34:04 +100098 error = xfs_attr_grab_log_assist(mp);
99 if (error)
100 return error;
101
Darrick J. Wongf4288f02022-06-05 18:51:22 -0700102 args->op_flags |= XFS_DA_OP_LOGGED;
Darrick J. Wongefc2efe2022-05-27 10:34:04 +1000103 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
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000114static int
Al Virob2968212016-04-10 20:48:24 -0400115xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
116 struct inode *inode, const char *name, void *value, size_t size)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000117{
Christoph Hellwige5171d72020-02-26 17:30:34 -0800118 struct xfs_da_args args = {
119 .dp = XFS_I(inode),
Christoph Hellwigd5f0f492020-02-26 17:30:42 -0800120 .attr_filter = handler->flags,
Christoph Hellwige5171d72020-02-26 17:30:34 -0800121 .name = name,
122 .namelen = strlen(name),
123 .value = value,
124 .valuelen = size,
125 };
126 int error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000127
Christoph Hellwige5171d72020-02-26 17:30:34 -0800128 error = xfs_attr_get(&args);
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000129 if (error)
130 return error;
Christoph Hellwige5171d72020-02-26 17:30:34 -0800131 return args.valuelen;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000132}
133
134static int
Christian Braunere65ce2a2021-01-21 14:19:27 +0100135xfs_xattr_set(const struct xattr_handler *handler,
Christian Brauner39f60c12023-01-13 12:49:23 +0100136 struct mnt_idmap *idmap, struct dentry *unused,
Christian Braunere65ce2a2021-01-21 14:19:27 +0100137 struct inode *inode, const char *name, const void *value,
138 size_t size, int flags)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000139{
Christoph Hellwiga2544622020-02-26 17:30:33 -0800140 struct xfs_da_args args = {
141 .dp = XFS_I(inode),
Christoph Hellwigd5f0f492020-02-26 17:30:42 -0800142 .attr_filter = handler->flags,
143 .attr_flags = flags,
Christoph Hellwiga2544622020-02-26 17:30:33 -0800144 .name = name,
145 .namelen = strlen(name),
146 .value = (void *)value,
147 .valuelen = size,
148 };
Brian Foster67d8e042015-11-03 12:40:59 +1100149 int error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000150
Darrick J. Wongefc2efe2022-05-27 10:34:04 +1000151 error = xfs_attr_change(&args);
Christoph Hellwigd5f0f492020-02-26 17:30:42 -0800152 if (!error && (handler->flags & XFS_ATTR_ROOT))
Christoph Hellwig5a3930e2020-02-26 17:30:41 -0800153 xfs_forget_acl(inode, name);
Brian Foster67d8e042015-11-03 12:40:59 +1100154 return error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000155}
156
Stephen Hemminger46e58762010-05-13 17:53:20 -0700157static const struct xattr_handler xfs_xattr_user_handler = {
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000158 .prefix = XATTR_USER_PREFIX,
Christoph Hellwig431547b2009-11-13 09:52:56 +0000159 .flags = 0, /* no flags implies user namespace */
160 .get = xfs_xattr_get,
161 .set = xfs_xattr_set,
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000162};
163
Stephen Hemminger46e58762010-05-13 17:53:20 -0700164static const struct xattr_handler xfs_xattr_trusted_handler = {
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000165 .prefix = XATTR_TRUSTED_PREFIX,
Christoph Hellwigd5f0f492020-02-26 17:30:42 -0800166 .flags = XFS_ATTR_ROOT,
Christoph Hellwig431547b2009-11-13 09:52:56 +0000167 .get = xfs_xattr_get,
168 .set = xfs_xattr_set,
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000169};
170
Stephen Hemminger46e58762010-05-13 17:53:20 -0700171static const struct xattr_handler xfs_xattr_security_handler = {
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000172 .prefix = XATTR_SECURITY_PREFIX,
Christoph Hellwigd5f0f492020-02-26 17:30:42 -0800173 .flags = XFS_ATTR_SECURE,
Christoph Hellwig431547b2009-11-13 09:52:56 +0000174 .get = xfs_xattr_get,
175 .set = xfs_xattr_set,
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000176};
177
Stephen Hemminger46e58762010-05-13 17:53:20 -0700178const struct xattr_handler *xfs_xattr_handlers[] = {
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000179 &xfs_xattr_user_handler,
180 &xfs_xattr_trusted_handler,
181 &xfs_xattr_security_handler,
Christoph Hellwigef14f0c2009-06-10 17:07:47 +0200182#ifdef CONFIG_XFS_POSIX_ACL
Christoph Hellwig2401dc22013-12-20 05:16:50 -0800183 &posix_acl_access_xattr_handler,
184 &posix_acl_default_xattr_handler,
Christoph Hellwigef14f0c2009-06-10 17:07:47 +0200185#endif
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000186 NULL
187};
188
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100189static void
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100190__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)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000196{
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100197 char *offset;
198 int arraytop;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000199
Darrick J. Wong3b500862019-02-13 11:15:17 -0800200 if (context->count < 0 || context->seen_enough)
201 return;
202
Christoph Hellwiga9c8c692020-02-26 17:30:37 -0800203 if (!context->buffer)
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100204 goto compute_size;
205
206 arraytop = context->count + prefix_len + namelen + 1;
207 if (arraytop > context->firstu) {
208 context->count = -1; /* insufficient space */
Artem Savkov791cc432016-09-14 07:40:35 +1000209 context->seen_enough = 1;
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100210 return;
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100211 }
Christoph Hellwiga9c8c692020-02-26 17:30:37 -0800212 offset = context->buffer + context->count;
Darrick J. Wongfd5beaf2022-11-28 17:24:42 -0800213 memcpy(offset, prefix, prefix_len);
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100214 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;
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100221 return;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000222}
223
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100224static void
Dave Chinnera9273ca2010-01-20 10:47:48 +1100225xfs_xattr_put_listent(
226 struct xfs_attr_list_context *context,
227 int flags,
228 unsigned char *name,
229 int namelen,
Eric Sandeene5bd12b2016-04-06 07:57:32 +1000230 int valuelen)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000231{
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100232 char *prefix;
233 int prefix_len;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000234
235 ASSERT(context->count >= 0);
236
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100237 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) {
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100242 __xfs_xattr_put_listent(
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100243 context, XATTR_SYSTEM_PREFIX,
244 XATTR_SYSTEM_PREFIX_LEN,
245 XATTR_POSIX_ACL_ACCESS,
246 strlen(XATTR_POSIX_ACL_ACCESS));
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100247 } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
248 strncmp(name, SGI_ACL_DEFAULT,
249 SGI_ACL_DEFAULT_SIZE) == 0) {
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100250 __xfs_xattr_put_listent(
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100251 context, XATTR_SYSTEM_PREFIX,
252 XATTR_SYSTEM_PREFIX_LEN,
253 XATTR_POSIX_ACL_DEFAULT,
254 strlen(XATTR_POSIX_ACL_DEFAULT));
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100255 }
256#endif
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000257
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100258 /*
259 * Only show root namespace entries if we are actually allowed to
260 * see them.
261 */
262 if (!capable(CAP_SYS_ADMIN))
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100263 return;
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100264
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;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000273 }
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000274
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100275 __xfs_xattr_put_listent(context, prefix, prefix_len, name,
276 namelen);
277 return;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000278}
279
280ssize_t
Eric Sandeen2a6fba62016-04-06 07:57:18 +1000281xfs_vn_listxattr(
282 struct dentry *dentry,
283 char *data,
284 size_t size)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000285{
286 struct xfs_attr_list_context context;
Eric Sandeen2a6fba62016-04-06 07:57:18 +1000287 struct inode *inode = d_inode(dentry);
288 int error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000289
290 /*
291 * First read the regular on-disk attributes.
292 */
293 memset(&context, 0, sizeof(context));
294 context.dp = XFS_I(inode);
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000295 context.resynch = 1;
Christoph Hellwiga9c8c692020-02-26 17:30:37 -0800296 context.buffer = size ? data : NULL;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000297 context.bufsize = size;
298 context.firstu = context.bufsize;
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100299 context.put_listent = xfs_xattr_put_listent;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000300
Christoph Hellwig17e1dd82020-02-26 17:30:39 -0800301 error = xfs_attr_list(&context);
Eric Sandeen2a6fba62016-04-06 07:57:18 +1000302 if (error)
303 return error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000304 if (context.count < 0)
305 return -ERANGE;
306
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000307 return context.count;
308}