~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/xfs/xfs_xattr.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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         /*
114          * Some xattrs must be resistant to allocation failure at ENOSPC, e.g.
115          * creating an inode with ACLs or security attributes requires the
116          * allocation of the xattr holding that information to succeed. Hence
117          * we allow xattrs in the VFS TRUSTED, SYSTEM, POSIX_ACL and SECURITY
118          * (LSM xattr) namespaces to dip into the reserve block pool to allow
119          * manipulation of these xattrs when at ENOSPC. These VFS xattr
120          * namespaces translate to the XFS_ATTR_ROOT and XFS_ATTR_SECURE on-disk
121          * namespaces.
122          *
123          * For most of these cases, these special xattrs will fit in the inode
124          * itself and so consume no extra space or only require temporary extra
125          * space while an overwrite is being made. Hence the use of the reserved
126          * pool is largely to avoid the worst case reservation from preventing
127          * the xattr from being created at ENOSPC.
128          */
129         return xfs_attr_set(args, op,
130                         args->attr_filter & (XFS_ATTR_ROOT | XFS_ATTR_SECURE));
131 }
132 
133 
134 static int
135 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
136                 struct inode *inode, const char *name, void *value, size_t size)
137 {
138         struct xfs_da_args      args = {
139                 .dp             = XFS_I(inode),
140                 .attr_filter    = handler->flags,
141                 .name           = name,
142                 .namelen        = strlen(name),
143                 .value          = value,
144                 .valuelen       = size,
145         };
146         int                     error;
147 
148         if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))
149                 return -EIO;
150 
151         error = xfs_attr_get(&args);
152         if (error)
153                 return error;
154         return args.valuelen;
155 }
156 
157 static inline enum xfs_attr_update
158 xfs_xattr_flags_to_op(
159         int             flags,
160         const void      *value)
161 {
162         if (!value)
163                 return XFS_ATTRUPDATE_REMOVE;
164         if (flags & XATTR_CREATE)
165                 return XFS_ATTRUPDATE_CREATE;
166         if (flags & XATTR_REPLACE)
167                 return XFS_ATTRUPDATE_REPLACE;
168         return XFS_ATTRUPDATE_UPSERT;
169 }
170 
171 static int
172 xfs_xattr_set(const struct xattr_handler *handler,
173               struct mnt_idmap *idmap, struct dentry *unused,
174               struct inode *inode, const char *name, const void *value,
175               size_t size, int flags)
176 {
177         struct xfs_da_args      args = {
178                 .dp             = XFS_I(inode),
179                 .attr_filter    = handler->flags,
180                 .name           = name,
181                 .namelen        = strlen(name),
182                 .value          = (void *)value,
183                 .valuelen       = size,
184         };
185         int                     error;
186 
187         error = xfs_attr_change(&args, xfs_xattr_flags_to_op(flags, value));
188         if (!error && (handler->flags & XFS_ATTR_ROOT))
189                 xfs_forget_acl(inode, name);
190         return error;
191 }
192 
193 static const struct xattr_handler xfs_xattr_user_handler = {
194         .prefix = XATTR_USER_PREFIX,
195         .flags  = 0, /* no flags implies user namespace */
196         .get    = xfs_xattr_get,
197         .set    = xfs_xattr_set,
198 };
199 
200 static const struct xattr_handler xfs_xattr_trusted_handler = {
201         .prefix = XATTR_TRUSTED_PREFIX,
202         .flags  = XFS_ATTR_ROOT,
203         .get    = xfs_xattr_get,
204         .set    = xfs_xattr_set,
205 };
206 
207 static const struct xattr_handler xfs_xattr_security_handler = {
208         .prefix = XATTR_SECURITY_PREFIX,
209         .flags  = XFS_ATTR_SECURE,
210         .get    = xfs_xattr_get,
211         .set    = xfs_xattr_set,
212 };
213 
214 const struct xattr_handler * const xfs_xattr_handlers[] = {
215         &xfs_xattr_user_handler,
216         &xfs_xattr_trusted_handler,
217         &xfs_xattr_security_handler,
218         NULL
219 };
220 
221 static void
222 __xfs_xattr_put_listent(
223         struct xfs_attr_list_context *context,
224         char *prefix,
225         int prefix_len,
226         unsigned char *name,
227         int namelen)
228 {
229         char *offset;
230         int arraytop;
231 
232         if (context->count < 0 || context->seen_enough)
233                 return;
234 
235         if (!context->buffer)
236                 goto compute_size;
237 
238         arraytop = context->count + prefix_len + namelen + 1;
239         if (arraytop > context->firstu) {
240                 context->count = -1;    /* insufficient space */
241                 context->seen_enough = 1;
242                 return;
243         }
244         offset = context->buffer + context->count;
245         memcpy(offset, prefix, prefix_len);
246         offset += prefix_len;
247         strncpy(offset, (char *)name, namelen);                 /* real name */
248         offset += namelen;
249         *offset = '\0';
250 
251 compute_size:
252         context->count += prefix_len + namelen + 1;
253         return;
254 }
255 
256 static void
257 xfs_xattr_put_listent(
258         struct xfs_attr_list_context *context,
259         int             flags,
260         unsigned char   *name,
261         int             namelen,
262         void            *value,
263         int             valuelen)
264 {
265         char *prefix;
266         int prefix_len;
267 
268         ASSERT(context->count >= 0);
269 
270         /* Don't expose private xattr namespaces. */
271         if (flags & XFS_ATTR_PRIVATE_NSP_MASK)
272                 return;
273 
274         if (flags & XFS_ATTR_ROOT) {
275 #ifdef CONFIG_XFS_POSIX_ACL
276                 if (namelen == SGI_ACL_FILE_SIZE &&
277                     strncmp(name, SGI_ACL_FILE,
278                             SGI_ACL_FILE_SIZE) == 0) {
279                         __xfs_xattr_put_listent(
280                                         context, XATTR_SYSTEM_PREFIX,
281                                         XATTR_SYSTEM_PREFIX_LEN,
282                                         XATTR_POSIX_ACL_ACCESS,
283                                         strlen(XATTR_POSIX_ACL_ACCESS));
284                 } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
285                          strncmp(name, SGI_ACL_DEFAULT,
286                                  SGI_ACL_DEFAULT_SIZE) == 0) {
287                         __xfs_xattr_put_listent(
288                                         context, XATTR_SYSTEM_PREFIX,
289                                         XATTR_SYSTEM_PREFIX_LEN,
290                                         XATTR_POSIX_ACL_DEFAULT,
291                                         strlen(XATTR_POSIX_ACL_DEFAULT));
292                 }
293 #endif
294 
295                 /*
296                  * Only show root namespace entries if we are actually allowed to
297                  * see them.
298                  */
299                 if (!capable(CAP_SYS_ADMIN))
300                         return;
301 
302                 prefix = XATTR_TRUSTED_PREFIX;
303                 prefix_len = XATTR_TRUSTED_PREFIX_LEN;
304         } else if (flags & XFS_ATTR_SECURE) {
305                 prefix = XATTR_SECURITY_PREFIX;
306                 prefix_len = XATTR_SECURITY_PREFIX_LEN;
307         } else {
308                 prefix = XATTR_USER_PREFIX;
309                 prefix_len = XATTR_USER_PREFIX_LEN;
310         }
311 
312         __xfs_xattr_put_listent(context, prefix, prefix_len, name,
313                                 namelen);
314         return;
315 }
316 
317 ssize_t
318 xfs_vn_listxattr(
319         struct dentry   *dentry,
320         char            *data,
321         size_t          size)
322 {
323         struct xfs_attr_list_context context;
324         struct inode    *inode = d_inode(dentry);
325         int             error;
326 
327         if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))
328                 return -EIO;
329 
330         /*
331          * First read the regular on-disk attributes.
332          */
333         memset(&context, 0, sizeof(context));
334         context.dp = XFS_I(inode);
335         context.resynch = 1;
336         context.buffer = size ? data : NULL;
337         context.bufsize = size;
338         context.firstu = context.bufsize;
339         context.put_listent = xfs_xattr_put_listent;
340 
341         error = xfs_attr_list(&context);
342         if (error)
343                 return error;
344         if (context.count < 0)
345                 return -ERANGE;
346 
347         return context.count;
348 }
349 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php