]> Git Repo - linux.git/blob - fs/xfs/xfs_xattr.c
Merge patch series "riscv: Extension parsing fixes"
[linux.git] / fs / xfs / xfs_xattr.c
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 #include "xfs_quota.h"
21
22 #include <linux/posix_acl_xattr.h>
23
24 /*
25  * Get permission to use log-assisted atomic exchange of file extents.
26  * Callers must not be running any transactions or hold any ILOCKs.
27  */
28 static inline int
29 xfs_attr_grab_log_assist(
30         struct xfs_mount        *mp)
31 {
32         int                     error = 0;
33
34         /* xattr update log intent items are already enabled */
35         if (xfs_is_using_logged_xattrs(mp))
36                 return 0;
37
38         /*
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.
43          */
44         if (!xfs_has_reflink(mp) && !xfs_has_rmapbt(mp))
45                 return -EOPNOTSUPP;
46
47         /* Enable log-assisted xattrs. */
48         error = xfs_add_incompat_log_feature(mp,
49                         XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
50         if (error)
51                 return error;
52         xfs_set_using_logged_xattrs(mp);
53
54         xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP,
55  "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!");
56
57         return 0;
58 }
59
60 static inline bool
61 xfs_attr_want_log_assist(
62         struct xfs_mount        *mp)
63 {
64 #ifdef DEBUG
65         /* Logged xattrs require a V5 super for log_incompat */
66         return xfs_has_crc(mp) && xfs_globals.larp;
67 #else
68         return false;
69 #endif
70 }
71
72 /*
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
76  * of @args.
77  */
78 int
79 xfs_attr_change(
80         struct xfs_da_args      *args,
81         enum xfs_attr_update    op)
82 {
83         struct xfs_mount        *mp = args->dp->i_mount;
84         int                     error;
85
86         if (xfs_is_shutdown(mp))
87                 return -EIO;
88
89         error = xfs_qm_dqattach(args->dp);
90         if (error)
91                 return error;
92
93         /*
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.
97          */
98         args->op_flags = XFS_DA_OP_OKNOENT;
99
100         if (xfs_attr_want_log_assist(mp)) {
101                 error = xfs_attr_grab_log_assist(mp);
102                 if (error)
103                         return error;
104
105                 args->op_flags |= XFS_DA_OP_LOGGED;
106         }
107
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);
112
113         return xfs_attr_set(args, op, args->attr_filter & XFS_ATTR_ROOT);
114 }
115
116
117 static int
118 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
119                 struct inode *inode, const char *name, void *value, size_t size)
120 {
121         struct xfs_da_args      args = {
122                 .dp             = XFS_I(inode),
123                 .attr_filter    = handler->flags,
124                 .name           = name,
125                 .namelen        = strlen(name),
126                 .value          = value,
127                 .valuelen       = size,
128         };
129         int                     error;
130
131         if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))
132                 return -EIO;
133
134         error = xfs_attr_get(&args);
135         if (error)
136                 return error;
137         return args.valuelen;
138 }
139
140 static inline enum xfs_attr_update
141 xfs_xattr_flags_to_op(
142         int             flags,
143         const void      *value)
144 {
145         if (!value)
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;
152 }
153
154 static int
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)
159 {
160         struct xfs_da_args      args = {
161                 .dp             = XFS_I(inode),
162                 .attr_filter    = handler->flags,
163                 .name           = name,
164                 .namelen        = strlen(name),
165                 .value          = (void *)value,
166                 .valuelen       = size,
167         };
168         int                     error;
169
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);
173         return error;
174 }
175
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,
181 };
182
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,
188 };
189
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,
195 };
196
197 const struct xattr_handler * const xfs_xattr_handlers[] = {
198         &xfs_xattr_user_handler,
199         &xfs_xattr_trusted_handler,
200         &xfs_xattr_security_handler,
201         NULL
202 };
203
204 static void
205 __xfs_xattr_put_listent(
206         struct xfs_attr_list_context *context,
207         char *prefix,
208         int prefix_len,
209         unsigned char *name,
210         int namelen)
211 {
212         char *offset;
213         int arraytop;
214
215         if (context->count < 0 || context->seen_enough)
216                 return;
217
218         if (!context->buffer)
219                 goto compute_size;
220
221         arraytop = context->count + prefix_len + namelen + 1;
222         if (arraytop > context->firstu) {
223                 context->count = -1;    /* insufficient space */
224                 context->seen_enough = 1;
225                 return;
226         }
227         offset = context->buffer + context->count;
228         memcpy(offset, prefix, prefix_len);
229         offset += prefix_len;
230         strncpy(offset, (char *)name, namelen);                 /* real name */
231         offset += namelen;
232         *offset = '\0';
233
234 compute_size:
235         context->count += prefix_len + namelen + 1;
236         return;
237 }
238
239 static void
240 xfs_xattr_put_listent(
241         struct xfs_attr_list_context *context,
242         int             flags,
243         unsigned char   *name,
244         int             namelen,
245         void            *value,
246         int             valuelen)
247 {
248         char *prefix;
249         int prefix_len;
250
251         ASSERT(context->count >= 0);
252
253         /* Don't expose private xattr namespaces. */
254         if (flags & XFS_ATTR_PRIVATE_NSP_MASK)
255                 return;
256
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));
275                 }
276 #endif
277
278                 /*
279                  * Only show root namespace entries if we are actually allowed to
280                  * see them.
281                  */
282                 if (!capable(CAP_SYS_ADMIN))
283                         return;
284
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;
290         } else {
291                 prefix = XATTR_USER_PREFIX;
292                 prefix_len = XATTR_USER_PREFIX_LEN;
293         }
294
295         __xfs_xattr_put_listent(context, prefix, prefix_len, name,
296                                 namelen);
297         return;
298 }
299
300 ssize_t
301 xfs_vn_listxattr(
302         struct dentry   *dentry,
303         char            *data,
304         size_t          size)
305 {
306         struct xfs_attr_list_context context;
307         struct inode    *inode = d_inode(dentry);
308         int             error;
309
310         if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))
311                 return -EIO;
312
313         /*
314          * First read the regular on-disk attributes.
315          */
316         memset(&context, 0, sizeof(context));
317         context.dp = XFS_I(inode);
318         context.resynch = 1;
319         context.buffer = size ? data : NULL;
320         context.bufsize = size;
321         context.firstu = context.bufsize;
322         context.put_listent = xfs_xattr_put_listent;
323
324         error = xfs_attr_list(&context);
325         if (error)
326                 return error;
327         if (context.count < 0)
328                 return -ERANGE;
329
330         return context.count;
331 }
This page took 0.05115 seconds and 4 git commands to generate.