Line data Source code
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 :
21 : #include <linux/posix_acl_xattr.h>
22 :
23 : /*
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 : */
30 : int
31 236871302 : xfs_attr_grab_log_assist(
32 : struct xfs_mount *mp)
33 : {
34 236871302 : int error = 0;
35 :
36 : /*
37 : * Protect ourselves from an idle log clearing the logged xattrs log
38 : * incompat feature bit.
39 : */
40 236871302 : xlog_use_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_XATTRS);
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 474398558 : if (xfs_sb_version_haslogxattrs(&mp->m_sb))
47 : return 0;
48 :
49 : /* Enable log-assisted xattrs. */
50 184556 : error = xfs_add_incompat_log_feature(mp,
51 : XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
52 184623 : if (error)
53 173 : goto drop_incompat;
54 :
55 184450 : 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;
59 : drop_incompat:
60 173 : xlog_drop_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_XATTRS);
61 173 : return error;
62 : }
63 :
64 : void
65 5000049 : xfs_attr_rele_log_assist(
66 : struct xfs_mount *mp)
67 : {
68 5000049 : xlog_drop_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_XATTRS);
69 4549007 : }
70 :
71 : static inline bool
72 325156963 : xfs_attr_want_log_assist(
73 : struct xfs_mount *mp)
74 : {
75 : #ifdef DEBUG
76 : /* Logged xattrs require a V5 super for log_incompat */
77 325156963 : return xfs_has_crc(mp) && xfs_globals.larp;
78 : #else
79 : return false;
80 : #endif
81 : }
82 :
83 : /*
84 : * Set or remove an xattr, having grabbed the appropriate logging resources
85 : * prior to calling libxfs.
86 : */
87 : int
88 325187300 : xfs_attr_change(
89 : struct xfs_da_args *args)
90 : {
91 325187300 : struct xfs_mount *mp = args->dp->i_mount;
92 325187300 : bool use_logging = false;
93 325187300 : int error;
94 :
95 325187300 : ASSERT(!(args->op_flags & XFS_DA_OP_LOGGED));
96 :
97 325187300 : if (xfs_attr_want_log_assist(mp)) {
98 4528680 : error = xfs_attr_grab_log_assist(mp);
99 4540291 : if (error)
100 : return error;
101 :
102 4540291 : args->op_flags |= XFS_DA_OP_LOGGED;
103 4540291 : use_logging = true;
104 : }
105 :
106 325269605 : if (args->value)
107 218381580 : args->op_flags &= ~XFS_DA_OP_REMOVE;
108 : else
109 106888025 : args->op_flags |= XFS_DA_OP_REMOVE;
110 :
111 325269605 : error = xfs_attr_set(args);
112 :
113 325584859 : if (use_logging)
114 4548654 : xfs_attr_rele_log_assist(mp);
115 : return error;
116 : }
117 :
118 :
119 : static int
120 78453108 : xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
121 : struct inode *inode, const char *name, void *value, size_t size)
122 : {
123 78453108 : struct xfs_da_args args = {
124 : .dp = XFS_I(inode),
125 78453108 : .attr_filter = handler->flags,
126 : .name = name,
127 : .namelen = strlen(name),
128 : .value = value,
129 : .valuelen = size,
130 78453108 : .owner = XFS_I(inode)->i_ino,
131 : };
132 78453108 : int error;
133 :
134 78453108 : error = xfs_attr_get(&args);
135 78350916 : if (error)
136 : return error;
137 23709129 : return args.valuelen;
138 : }
139 :
140 : static int
141 314866996 : xfs_xattr_set(const struct xattr_handler *handler,
142 : struct mnt_idmap *idmap, struct dentry *unused,
143 : struct inode *inode, const char *name, const void *value,
144 : size_t size, int flags)
145 : {
146 314866996 : struct xfs_da_args args = {
147 : .dp = XFS_I(inode),
148 314866996 : .attr_filter = handler->flags,
149 : .attr_flags = flags,
150 : .name = name,
151 : .namelen = strlen(name),
152 : .value = (void *)value,
153 : .valuelen = size,
154 314866996 : .owner = XFS_I(inode)->i_ino,
155 : };
156 314866996 : int error;
157 :
158 314866996 : error = xfs_attr_change(&args);
159 315099744 : if (!error && (handler->flags & XFS_ATTR_ROOT))
160 453558 : xfs_forget_acl(inode, name);
161 315099730 : return error;
162 : }
163 :
164 : static const struct xattr_handler xfs_xattr_user_handler = {
165 : .prefix = XATTR_USER_PREFIX,
166 : .flags = 0, /* no flags implies user namespace */
167 : .get = xfs_xattr_get,
168 : .set = xfs_xattr_set,
169 : };
170 :
171 : static const struct xattr_handler xfs_xattr_trusted_handler = {
172 : .prefix = XATTR_TRUSTED_PREFIX,
173 : .flags = XFS_ATTR_ROOT,
174 : .get = xfs_xattr_get,
175 : .set = xfs_xattr_set,
176 : };
177 :
178 : static const struct xattr_handler xfs_xattr_security_handler = {
179 : .prefix = XATTR_SECURITY_PREFIX,
180 : .flags = XFS_ATTR_SECURE,
181 : .get = xfs_xattr_get,
182 : .set = xfs_xattr_set,
183 : };
184 :
185 : const struct xattr_handler *xfs_xattr_handlers[] = {
186 : &xfs_xattr_user_handler,
187 : &xfs_xattr_trusted_handler,
188 : &xfs_xattr_security_handler,
189 : NULL
190 : };
191 :
192 : static void
193 1503692527 : __xfs_xattr_put_listent(
194 : struct xfs_attr_list_context *context,
195 : char *prefix,
196 : int prefix_len,
197 : unsigned char *name,
198 : int namelen)
199 : {
200 1503692527 : char *offset;
201 1503692527 : int arraytop;
202 :
203 1503692527 : if (context->count < 0 || context->seen_enough)
204 : return;
205 :
206 1503692516 : if (!context->buffer)
207 376752342 : goto compute_size;
208 :
209 1126940174 : arraytop = context->count + prefix_len + namelen + 1;
210 1126940174 : if (arraytop > context->firstu) {
211 44 : context->count = -1; /* insufficient space */
212 44 : context->seen_enough = 1;
213 44 : return;
214 : }
215 1126940130 : offset = context->buffer + context->count;
216 2253880260 : memcpy(offset, prefix, prefix_len);
217 1126940130 : offset += prefix_len;
218 1126940130 : strncpy(offset, (char *)name, namelen); /* real name */
219 1126940130 : offset += namelen;
220 1126940130 : *offset = '\0';
221 :
222 1503692472 : compute_size:
223 1503692472 : context->count += prefix_len + namelen + 1;
224 1503692472 : return;
225 : }
226 :
227 : static void
228 1610800640 : xfs_xattr_put_listent(
229 : struct xfs_attr_list_context *context,
230 : int flags,
231 : unsigned char *name,
232 : int namelen,
233 : void *value,
234 : int valuelen)
235 : {
236 1610800640 : char *prefix;
237 1610800640 : int prefix_len;
238 :
239 1610800640 : ASSERT(context->count >= 0);
240 :
241 1610800640 : if (flags & XFS_ATTR_PARENT)
242 : return;
243 :
244 1502916334 : if (flags & XFS_ATTR_ROOT) {
245 : #ifdef CONFIG_XFS_POSIX_ACL
246 4565 : if (namelen == SGI_ACL_FILE_SIZE &&
247 11 : strncmp(name, SGI_ACL_FILE,
248 : SGI_ACL_FILE_SIZE) == 0) {
249 11 : __xfs_xattr_put_listent(
250 : context, XATTR_SYSTEM_PREFIX,
251 : XATTR_SYSTEM_PREFIX_LEN,
252 : XATTR_POSIX_ACL_ACCESS,
253 : strlen(XATTR_POSIX_ACL_ACCESS));
254 4554 : } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
255 0 : strncmp(name, SGI_ACL_DEFAULT,
256 : SGI_ACL_DEFAULT_SIZE) == 0) {
257 0 : __xfs_xattr_put_listent(
258 : context, XATTR_SYSTEM_PREFIX,
259 : XATTR_SYSTEM_PREFIX_LEN,
260 : XATTR_POSIX_ACL_DEFAULT,
261 : strlen(XATTR_POSIX_ACL_DEFAULT));
262 : }
263 : #endif
264 :
265 : /*
266 : * Only show root namespace entries if we are actually allowed to
267 : * see them.
268 : */
269 4565 : if (!capable(CAP_SYS_ADMIN))
270 : return;
271 :
272 : prefix = XATTR_TRUSTED_PREFIX;
273 : prefix_len = XATTR_TRUSTED_PREFIX_LEN;
274 1502911769 : } else if (flags & XFS_ATTR_SECURE) {
275 : prefix = XATTR_SECURITY_PREFIX;
276 : prefix_len = XATTR_SECURITY_PREFIX_LEN;
277 : } else {
278 1502868583 : prefix = XATTR_USER_PREFIX;
279 1502868583 : prefix_len = XATTR_USER_PREFIX_LEN;
280 : }
281 :
282 1502916334 : __xfs_xattr_put_listent(context, prefix, prefix_len, name,
283 : namelen);
284 1502916334 : return;
285 : }
286 :
287 : ssize_t
288 108160204 : xfs_vn_listxattr(
289 : struct dentry *dentry,
290 : char *data,
291 : size_t size)
292 : {
293 108160204 : struct xfs_attr_list_context context;
294 108160204 : struct inode *inode = d_inode(dentry);
295 108160204 : int error;
296 :
297 : /*
298 : * First read the regular on-disk attributes.
299 : */
300 108160204 : memset(&context, 0, sizeof(context));
301 108160204 : context.dp = XFS_I(inode);
302 108160204 : context.resynch = 1;
303 108160204 : context.buffer = size ? data : NULL;
304 108160204 : context.bufsize = size;
305 108160204 : context.firstu = context.bufsize;
306 108160204 : context.put_listent = xfs_xattr_put_listent;
307 :
308 108160204 : error = xfs_attr_list(&context);
309 108169043 : if (error)
310 11 : return error;
311 108169032 : if (context.count < 0)
312 44 : return -ERANGE;
313 :
314 : return context.count;
315 : }
|