blob: 383f0203d103744f79137ff1bba5edee193529ba [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"
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100012#include "xfs_inode.h"
13#include "xfs_attr.h"
Darrick J. Wong5f213dd2019-11-06 17:19:33 -080014#include "xfs_acl.h"
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100015
16#include <linux/posix_acl_xattr.h>
17#include <linux/xattr.h>
18
19
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100020static int
Al Virob2968212016-04-10 20:48:24 -040021xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
22 struct inode *inode, const char *name, void *value, size_t size)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100023{
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +020024 int xflags = handler->flags;
Al Virob2968212016-04-10 20:48:24 -040025 struct xfs_inode *ip = XFS_I(inode);
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100026 int error, asize = size;
27
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100028 /* Convert Linux syscall to XFS internal ATTR flags */
29 if (!size) {
30 xflags |= ATTR_KERNOVAL;
31 value = NULL;
32 }
33
Dave Chinnerddbca702019-08-29 09:04:10 -070034 error = xfs_attr_get(ip, name, (unsigned char **)&value, &asize, xflags);
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100035 if (error)
36 return error;
37 return asize;
38}
39
Andreas Gruenbacher47e1bf62015-11-03 12:56:17 +110040void
41xfs_forget_acl(
42 struct inode *inode,
43 const char *name,
44 int xflags)
45{
46 /*
47 * Invalidate any cached ACLs if the user has bypassed the ACL
48 * interface. We don't validate the content whatsoever so it is caller
49 * responsibility to provide data in valid format and ensure i_mode is
50 * consistent.
51 */
52 if (xflags & ATTR_ROOT) {
53#ifdef CONFIG_XFS_POSIX_ACL
54 if (!strcmp(name, SGI_ACL_FILE))
55 forget_cached_acl(inode, ACL_TYPE_ACCESS);
56 else if (!strcmp(name, SGI_ACL_DEFAULT))
57 forget_cached_acl(inode, ACL_TYPE_DEFAULT);
58#endif
59 }
60}
61
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100062static int
Al Viro59301222016-05-27 10:19:30 -040063xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
64 struct inode *inode, const char *name, const void *value,
65 size_t size, int flags)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100066{
Linus Torvalds5d2eb542015-11-13 18:02:30 -080067 int xflags = handler->flags;
Al Viro59301222016-05-27 10:19:30 -040068 struct xfs_inode *ip = XFS_I(inode);
Brian Foster67d8e042015-11-03 12:40:59 +110069 int error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100070
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100071 /* Convert Linux syscall to XFS internal ATTR flags */
72 if (flags & XATTR_CREATE)
73 xflags |= ATTR_CREATE;
74 if (flags & XATTR_REPLACE)
75 xflags |= ATTR_REPLACE;
76
77 if (!value)
Dave Chinner24513372014-06-25 14:58:08 +100078 return xfs_attr_remove(ip, (unsigned char *)name, xflags);
Brian Foster67d8e042015-11-03 12:40:59 +110079 error = xfs_attr_set(ip, (unsigned char *)name,
Dave Chinnera9273ca2010-01-20 10:47:48 +110080 (void *)value, size, xflags);
Andreas Gruenbacher47e1bf62015-11-03 12:56:17 +110081 if (!error)
Al Viro59301222016-05-27 10:19:30 -040082 xfs_forget_acl(inode, name, xflags);
Brian Foster67d8e042015-11-03 12:40:59 +110083
84 return error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100085}
86
Stephen Hemminger46e58762010-05-13 17:53:20 -070087static const struct xattr_handler xfs_xattr_user_handler = {
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100088 .prefix = XATTR_USER_PREFIX,
Christoph Hellwig431547b2009-11-13 09:52:56 +000089 .flags = 0, /* no flags implies user namespace */
90 .get = xfs_xattr_get,
91 .set = xfs_xattr_set,
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100092};
93
Stephen Hemminger46e58762010-05-13 17:53:20 -070094static const struct xattr_handler xfs_xattr_trusted_handler = {
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100095 .prefix = XATTR_TRUSTED_PREFIX,
Christoph Hellwig431547b2009-11-13 09:52:56 +000096 .flags = ATTR_ROOT,
97 .get = xfs_xattr_get,
98 .set = xfs_xattr_set,
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +100099};
100
Stephen Hemminger46e58762010-05-13 17:53:20 -0700101static const struct xattr_handler xfs_xattr_security_handler = {
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000102 .prefix = XATTR_SECURITY_PREFIX,
Christoph Hellwig431547b2009-11-13 09:52:56 +0000103 .flags = ATTR_SECURE,
104 .get = xfs_xattr_get,
105 .set = xfs_xattr_set,
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000106};
107
Stephen Hemminger46e58762010-05-13 17:53:20 -0700108const struct xattr_handler *xfs_xattr_handlers[] = {
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000109 &xfs_xattr_user_handler,
110 &xfs_xattr_trusted_handler,
111 &xfs_xattr_security_handler,
Christoph Hellwigef14f0c2009-06-10 17:07:47 +0200112#ifdef CONFIG_XFS_POSIX_ACL
Christoph Hellwig2401dc22013-12-20 05:16:50 -0800113 &posix_acl_access_xattr_handler,
114 &posix_acl_default_xattr_handler,
Christoph Hellwigef14f0c2009-06-10 17:07:47 +0200115#endif
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000116 NULL
117};
118
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100119static void
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100120__xfs_xattr_put_listent(
121 struct xfs_attr_list_context *context,
122 char *prefix,
123 int prefix_len,
124 unsigned char *name,
125 int namelen)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000126{
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100127 char *offset;
128 int arraytop;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000129
Darrick J. Wong3b500862019-02-13 11:15:17 -0800130 if (context->count < 0 || context->seen_enough)
131 return;
132
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100133 if (!context->alist)
134 goto compute_size;
135
136 arraytop = context->count + prefix_len + namelen + 1;
137 if (arraytop > context->firstu) {
138 context->count = -1; /* insufficient space */
Artem Savkov791cc432016-09-14 07:40:35 +1000139 context->seen_enough = 1;
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100140 return;
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100141 }
142 offset = (char *)context->alist + context->count;
143 strncpy(offset, prefix, prefix_len);
144 offset += prefix_len;
145 strncpy(offset, (char *)name, namelen); /* real name */
146 offset += namelen;
147 *offset = '\0';
148
149compute_size:
150 context->count += prefix_len + namelen + 1;
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100151 return;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000152}
153
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100154static void
Dave Chinnera9273ca2010-01-20 10:47:48 +1100155xfs_xattr_put_listent(
156 struct xfs_attr_list_context *context,
157 int flags,
158 unsigned char *name,
159 int namelen,
Eric Sandeene5bd12b2016-04-06 07:57:32 +1000160 int valuelen)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000161{
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100162 char *prefix;
163 int prefix_len;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000164
165 ASSERT(context->count >= 0);
166
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100167 if (flags & XFS_ATTR_ROOT) {
168#ifdef CONFIG_XFS_POSIX_ACL
169 if (namelen == SGI_ACL_FILE_SIZE &&
170 strncmp(name, SGI_ACL_FILE,
171 SGI_ACL_FILE_SIZE) == 0) {
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100172 __xfs_xattr_put_listent(
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100173 context, XATTR_SYSTEM_PREFIX,
174 XATTR_SYSTEM_PREFIX_LEN,
175 XATTR_POSIX_ACL_ACCESS,
176 strlen(XATTR_POSIX_ACL_ACCESS));
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100177 } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
178 strncmp(name, SGI_ACL_DEFAULT,
179 SGI_ACL_DEFAULT_SIZE) == 0) {
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100180 __xfs_xattr_put_listent(
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100181 context, XATTR_SYSTEM_PREFIX,
182 XATTR_SYSTEM_PREFIX_LEN,
183 XATTR_POSIX_ACL_DEFAULT,
184 strlen(XATTR_POSIX_ACL_DEFAULT));
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100185 }
186#endif
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000187
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100188 /*
189 * Only show root namespace entries if we are actually allowed to
190 * see them.
191 */
192 if (!capable(CAP_SYS_ADMIN))
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100193 return;
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100194
195 prefix = XATTR_TRUSTED_PREFIX;
196 prefix_len = XATTR_TRUSTED_PREFIX_LEN;
197 } else if (flags & XFS_ATTR_SECURE) {
198 prefix = XATTR_SECURITY_PREFIX;
199 prefix_len = XATTR_SECURITY_PREFIX_LEN;
200 } else {
201 prefix = XATTR_USER_PREFIX;
202 prefix_len = XATTR_USER_PREFIX_LEN;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000203 }
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000204
Eric Sandeenf7a136a2016-12-05 12:32:14 +1100205 __xfs_xattr_put_listent(context, prefix, prefix_len, name,
206 namelen);
207 return;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000208}
209
210ssize_t
Eric Sandeen2a6fba62016-04-06 07:57:18 +1000211xfs_vn_listxattr(
212 struct dentry *dentry,
213 char *data,
214 size_t size)
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000215{
216 struct xfs_attr_list_context context;
217 struct attrlist_cursor_kern cursor = { 0 };
Eric Sandeen2a6fba62016-04-06 07:57:18 +1000218 struct inode *inode = d_inode(dentry);
219 int error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000220
221 /*
222 * First read the regular on-disk attributes.
223 */
224 memset(&context, 0, sizeof(context));
225 context.dp = XFS_I(inode);
226 context.cursor = &cursor;
227 context.resynch = 1;
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100228 context.alist = size ? data : NULL;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000229 context.bufsize = size;
230 context.firstu = context.bufsize;
Andreas Gruenbacher5d92b752015-12-02 14:44:40 +0100231 context.put_listent = xfs_xattr_put_listent;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000232
Eric Sandeen2a6fba62016-04-06 07:57:18 +1000233 error = xfs_attr_list_int(&context);
234 if (error)
235 return error;
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000236 if (context.count < 0)
237 return -ERANGE;
238
Lachlan McIlroyf9e09f02008-06-23 13:34:09 +1000239 return context.count;
240}