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 227749403 : xfs_attr_grab_log_assist(
32 : struct xfs_mount *mp)
33 : {
34 227749403 : int error = 0;
35 :
36 : /*
37 : * Protect ourselves from an idle log clearing the logged xattrs log
38 : * incompat feature bit.
39 : */
40 227749403 : 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 456064368 : if (xfs_sb_version_haslogxattrs(&mp->m_sb))
47 : return 0;
48 :
49 : /* Enable log-assisted xattrs. */
50 162662 : error = xfs_add_incompat_log_feature(mp,
51 : XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
52 162782 : if (error)
53 177 : goto drop_incompat;
54 :
55 162605 : 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 177 : xlog_drop_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_XATTRS);
61 177 : return error;
62 : }
63 :
64 : void
65 11330561 : xfs_attr_rele_log_assist(
66 : struct xfs_mount *mp)
67 : {
68 11330561 : xlog_drop_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_XATTRS);
69 3991291 : }
70 :
71 : static inline bool
72 184275330 : 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 184275330 : 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 184341593 : xfs_attr_change(
89 : struct xfs_da_args *args)
90 : {
91 184341593 : struct xfs_mount *mp = args->dp->i_mount;
92 184341593 : bool use_logging = false;
93 184341593 : int error;
94 :
95 184341593 : ASSERT(!(args->op_flags & XFS_DA_OP_LOGGED));
96 :
97 184341593 : if (xfs_attr_want_log_assist(mp)) {
98 3985022 : error = xfs_attr_grab_log_assist(mp);
99 3991008 : if (error)
100 : return error;
101 :
102 3991008 : args->op_flags |= XFS_DA_OP_LOGGED;
103 3991008 : use_logging = true;
104 : }
105 :
106 184416596 : if (args->value)
107 121083039 : args->op_flags &= ~XFS_DA_OP_REMOVE;
108 : else
109 63333557 : args->op_flags |= XFS_DA_OP_REMOVE;
110 :
111 184416596 : error = xfs_attr_set(args);
112 :
113 184439372 : if (use_logging)
114 3990642 : xfs_attr_rele_log_assist(mp);
115 : return error;
116 : }
117 :
118 :
119 : static int
120 57838487 : 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 57838487 : struct xfs_da_args args = {
124 : .dp = XFS_I(inode),
125 57838487 : .attr_filter = handler->flags,
126 : .name = name,
127 : .namelen = strlen(name),
128 : .value = value,
129 : .valuelen = size,
130 57838487 : .owner = XFS_I(inode)->i_ino,
131 : };
132 57838487 : int error;
133 :
134 57838487 : error = xfs_attr_get(&args);
135 57760465 : if (error)
136 : return error;
137 13200538 : return args.valuelen;
138 : }
139 :
140 : static int
141 173999807 : 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 173999807 : struct xfs_da_args args = {
147 : .dp = XFS_I(inode),
148 173999807 : .attr_filter = handler->flags,
149 : .attr_flags = flags,
150 : .name = name,
151 : .namelen = strlen(name),
152 : .value = (void *)value,
153 : .valuelen = size,
154 173999807 : .owner = XFS_I(inode)->i_ino,
155 : };
156 173999807 : int error;
157 :
158 173999807 : error = xfs_attr_change(&args);
159 173973481 : if (!error && (handler->flags & XFS_ATTR_ROOT))
160 462021 : xfs_forget_acl(inode, name);
161 173973411 : 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 811981479 : __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 811981479 : char *offset;
201 811981479 : int arraytop;
202 :
203 811981479 : if (context->count < 0 || context->seen_enough)
204 : return;
205 :
206 811981468 : if (!context->buffer)
207 203510414 : goto compute_size;
208 :
209 608471054 : arraytop = context->count + prefix_len + namelen + 1;
210 608471054 : if (arraytop > context->firstu) {
211 44 : context->count = -1; /* insufficient space */
212 44 : context->seen_enough = 1;
213 44 : return;
214 : }
215 608471010 : offset = context->buffer + context->count;
216 1216942020 : memcpy(offset, prefix, prefix_len);
217 608471010 : offset += prefix_len;
218 608471010 : strncpy(offset, (char *)name, namelen); /* real name */
219 608471010 : offset += namelen;
220 608471010 : *offset = '\0';
221 :
222 811981424 : compute_size:
223 811981424 : context->count += prefix_len + namelen + 1;
224 811981424 : return;
225 : }
226 :
227 : static void
228 871060161 : 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 871060161 : char *prefix;
237 871060161 : int prefix_len;
238 :
239 871060161 : ASSERT(context->count >= 0);
240 :
241 871060161 : if (flags & XFS_ATTR_PARENT)
242 : return;
243 :
244 811567918 : if (flags & XFS_ATTR_ROOT) {
245 : #ifdef CONFIG_XFS_POSIX_ACL
246 4561 : 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 4550 : } 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 4561 : if (!capable(CAP_SYS_ADMIN))
270 : return;
271 :
272 : prefix = XATTR_TRUSTED_PREFIX;
273 : prefix_len = XATTR_TRUSTED_PREFIX_LEN;
274 811563357 : } else if (flags & XFS_ATTR_SECURE) {
275 : prefix = XATTR_SECURITY_PREFIX;
276 : prefix_len = XATTR_SECURITY_PREFIX_LEN;
277 : } else {
278 811556213 : prefix = XATTR_USER_PREFIX;
279 811556213 : prefix_len = XATTR_USER_PREFIX_LEN;
280 : }
281 :
282 811567918 : __xfs_xattr_put_listent(context, prefix, prefix_len, name,
283 : namelen);
284 811567918 : return;
285 : }
286 :
287 : ssize_t
288 59725524 : xfs_vn_listxattr(
289 : struct dentry *dentry,
290 : char *data,
291 : size_t size)
292 : {
293 59725524 : struct xfs_attr_list_context context;
294 59725524 : struct inode *inode = d_inode(dentry);
295 59725524 : int error;
296 :
297 : /*
298 : * First read the regular on-disk attributes.
299 : */
300 59725524 : memset(&context, 0, sizeof(context));
301 59725524 : context.dp = XFS_I(inode);
302 59725524 : context.resynch = 1;
303 59725524 : context.buffer = size ? data : NULL;
304 59725524 : context.bufsize = size;
305 59725524 : context.firstu = context.bufsize;
306 59725524 : context.put_listent = xfs_xattr_put_listent;
307 :
308 59725524 : error = xfs_attr_list(&context);
309 59728794 : if (error)
310 12 : return error;
311 59728782 : if (context.count < 0)
312 44 : return -ERANGE;
313 :
314 : return context.count;
315 : }
|