]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - fs/aufs/xattr.c
tracing/histogram: Fix sorting on old "cpu" value
[mirror_ubuntu-jammy-kernel.git] / fs / aufs / xattr.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2014-2021 Junjiro R. Okajima
4 *
5 * This program, aufs is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * handling xattr functions
21 */
22
23 #include <linux/fs.h>
24 #include <linux/posix_acl_xattr.h>
25 #include <linux/xattr.h>
26 #include "aufs.h"
27
28 static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags)
29 {
30 if (!ignore_flags)
31 goto out;
32 switch (err) {
33 case -ENOMEM:
34 case -EDQUOT:
35 goto out;
36 }
37
38 if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) {
39 err = 0;
40 goto out;
41 }
42
43 #define cmp(brattr, prefix) do { \
44 if (!strncmp(name, XATTR_##prefix##_PREFIX, \
45 XATTR_##prefix##_PREFIX_LEN)) { \
46 if (ignore_flags & AuBrAttr_ICEX_##brattr) \
47 err = 0; \
48 goto out; \
49 } \
50 } while (0)
51
52 cmp(SEC, SECURITY);
53 cmp(SYS, SYSTEM);
54 cmp(TR, TRUSTED);
55 cmp(USR, USER);
56 #undef cmp
57
58 if (ignore_flags & AuBrAttr_ICEX_OTH)
59 err = 0;
60
61 out:
62 return err;
63 }
64
65 static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1;
66
67 static int au_do_cpup_xattr(struct path *h_dst, struct path *h_src,
68 char *name, char **buf, unsigned int ignore_flags,
69 unsigned int verbose)
70 {
71 int err;
72 ssize_t ssz;
73 struct inode *h_idst;
74 struct dentry *h_dst_dentry, *h_src_dentry;
75 struct user_namespace *h_dst_userns, *h_src_userns;
76
77 h_src_userns = mnt_user_ns(h_src->mnt);
78 h_src_dentry = h_src->dentry;
79 ssz = vfs_getxattr_alloc(h_src_userns, h_src_dentry, name, buf, 0,
80 GFP_NOFS);
81 err = ssz;
82 if (unlikely(err <= 0)) {
83 if (err == -ENODATA
84 || (err == -EOPNOTSUPP
85 && ((ignore_flags & au_xattr_out_of_list)
86 || (au_test_nfs_noacl(d_inode(h_src_dentry))
87 && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS)
88 || !strcmp(name,
89 XATTR_NAME_POSIX_ACL_DEFAULT))))
90 ))
91 err = 0;
92 if (err && (verbose || au_debug_test()))
93 pr_err("%s, err %d\n", name, err);
94 goto out;
95 }
96
97 /* unlock it temporary */
98 h_dst_userns = mnt_user_ns(h_dst->mnt);
99 h_dst_dentry = h_dst->dentry;
100 h_idst = d_inode(h_dst_dentry);
101 inode_unlock(h_idst);
102 err = vfsub_setxattr(h_dst_userns, h_dst_dentry, name, *buf, ssz,
103 /*flags*/0);
104 inode_lock_nested(h_idst, AuLsc_I_CHILD2);
105 if (unlikely(err)) {
106 if (verbose || au_debug_test())
107 pr_err("%s, err %d\n", name, err);
108 err = au_xattr_ignore(err, name, ignore_flags);
109 }
110
111 out:
112 return err;
113 }
114
115 int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags,
116 unsigned int verbose)
117 {
118 int err, unlocked, acl_access, acl_default;
119 ssize_t ssz;
120 struct dentry *h_dst_dentry, *h_src_dentry;
121 struct inode *h_isrc, *h_idst;
122 char *value, *p, *o, *e;
123
124 /* try stopping to update the source inode while we are referencing */
125 /* there should not be the parent-child relationship between them */
126 h_dst_dentry = h_dst->dentry;
127 h_idst = d_inode(h_dst_dentry);
128 h_src_dentry = h_src->dentry;
129 h_isrc = d_inode(h_src_dentry);
130 inode_unlock(h_idst);
131 inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD);
132 inode_lock_nested(h_idst, AuLsc_I_CHILD2);
133 unlocked = 0;
134
135 /* some filesystems don't list POSIX ACL, for example tmpfs */
136 ssz = vfs_listxattr(h_src_dentry, NULL, 0);
137 err = ssz;
138 if (unlikely(err < 0)) {
139 AuTraceErr(err);
140 if (err == -ENODATA
141 || err == -EOPNOTSUPP)
142 err = 0; /* ignore */
143 goto out;
144 }
145
146 err = 0;
147 p = NULL;
148 o = NULL;
149 if (ssz) {
150 err = -ENOMEM;
151 p = kmalloc(ssz, GFP_NOFS);
152 o = p;
153 if (unlikely(!p))
154 goto out;
155 err = vfs_listxattr(h_src_dentry, p, ssz);
156 }
157 inode_unlock_shared(h_isrc);
158 unlocked = 1;
159 AuDbg("err %d, ssz %zd\n", err, ssz);
160 if (unlikely(err < 0))
161 goto out_free;
162
163 err = 0;
164 e = p + ssz;
165 value = NULL;
166 acl_access = 0;
167 acl_default = 0;
168 while (!err && p < e) {
169 acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS,
170 sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1);
171 acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT,
172 sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)
173 - 1);
174 err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags,
175 verbose);
176 p += strlen(p) + 1;
177 }
178 AuTraceErr(err);
179 ignore_flags |= au_xattr_out_of_list;
180 if (!err && !acl_access) {
181 err = au_do_cpup_xattr(h_dst, h_src,
182 XATTR_NAME_POSIX_ACL_ACCESS, &value,
183 ignore_flags, verbose);
184 AuTraceErr(err);
185 }
186 if (!err && !acl_default) {
187 err = au_do_cpup_xattr(h_dst, h_src,
188 XATTR_NAME_POSIX_ACL_DEFAULT, &value,
189 ignore_flags, verbose);
190 AuTraceErr(err);
191 }
192
193 au_kfree_try_rcu(value);
194
195 out_free:
196 au_kfree_try_rcu(o);
197 out:
198 if (!unlocked)
199 inode_unlock_shared(h_isrc);
200 AuTraceErr(err);
201 return err;
202 }
203
204 /* ---------------------------------------------------------------------- */
205
206 static int au_smack_reentering(struct super_block *sb)
207 {
208 #if IS_ENABLED(CONFIG_SECURITY_SMACK) || IS_ENABLED(CONFIG_SECURITY_SELINUX)
209 /*
210 * as a part of lookup, smack_d_instantiate() is called, and it calls
211 * i_op->getxattr(). ouch.
212 */
213 return si_pid_test(sb);
214 #else
215 return 0;
216 #endif
217 }
218
219 enum {
220 AU_XATTR_LIST,
221 AU_XATTR_GET
222 };
223
224 struct au_lgxattr {
225 int type;
226 union {
227 struct {
228 char *list;
229 size_t size;
230 } list;
231 struct {
232 const char *name;
233 void *value;
234 size_t size;
235 } get;
236 } u;
237 };
238
239 static ssize_t au_lgxattr(struct dentry *dentry, struct inode *inode,
240 struct au_lgxattr *arg)
241 {
242 ssize_t err;
243 int reenter;
244 struct path h_path;
245 struct super_block *sb;
246
247 sb = dentry->d_sb;
248 reenter = au_smack_reentering(sb);
249 if (!reenter) {
250 err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
251 if (unlikely(err))
252 goto out;
253 }
254 err = au_h_path_getattr(dentry, inode, /*force*/1, &h_path, reenter);
255 if (unlikely(err))
256 goto out_si;
257 if (unlikely(!h_path.dentry))
258 /* illegally overlapped or something */
259 goto out_di; /* pretending success */
260
261 /* always topmost entry only */
262 switch (arg->type) {
263 case AU_XATTR_LIST:
264 err = vfs_listxattr(h_path.dentry,
265 arg->u.list.list, arg->u.list.size);
266 break;
267 case AU_XATTR_GET:
268 AuDebugOn(d_is_negative(h_path.dentry));
269 err = vfs_getxattr(mnt_user_ns(h_path.mnt), h_path.dentry,
270 arg->u.get.name, arg->u.get.value,
271 arg->u.get.size);
272 break;
273 }
274
275 out_di:
276 if (!reenter)
277 di_read_unlock(dentry, AuLock_IR);
278 out_si:
279 if (!reenter)
280 si_read_unlock(sb);
281 out:
282 AuTraceErr(err);
283 return err;
284 }
285
286 ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size)
287 {
288 struct au_lgxattr arg = {
289 .type = AU_XATTR_LIST,
290 .u.list = {
291 .list = list,
292 .size = size
293 },
294 };
295
296 return au_lgxattr(dentry, /*inode*/NULL, &arg);
297 }
298
299 static ssize_t au_getxattr(struct dentry *dentry, struct inode *inode,
300 const char *name, void *value, size_t size)
301 {
302 struct au_lgxattr arg = {
303 .type = AU_XATTR_GET,
304 .u.get = {
305 .name = name,
306 .value = value,
307 .size = size
308 },
309 };
310
311 return au_lgxattr(dentry, inode, &arg);
312 }
313
314 static int au_setxattr(struct dentry *dentry, struct inode *inode,
315 const char *name, const void *value, size_t size,
316 int flags)
317 {
318 struct au_sxattr arg = {
319 .type = AU_XATTR_SET,
320 .u.set = {
321 .name = name,
322 .value = value,
323 .size = size,
324 .flags = flags
325 },
326 };
327
328 return au_sxattr(dentry, inode, &arg);
329 }
330
331 /* ---------------------------------------------------------------------- */
332
333 static int au_xattr_get(const struct xattr_handler *handler,
334 struct dentry *dentry, struct inode *inode,
335 const char *name, void *buffer, size_t size)
336 {
337 return au_getxattr(dentry, inode, name, buffer, size);
338 }
339
340 static int au_xattr_set(const struct xattr_handler *handler,
341 struct user_namespace *userns,
342 struct dentry *dentry, struct inode *inode,
343 const char *name, const void *value, size_t size,
344 int flags)
345 {
346 return au_setxattr(dentry, inode, name, value, size, flags);
347 }
348
349 static const struct xattr_handler au_xattr_handler = {
350 .name = "",
351 .prefix = "",
352 .get = au_xattr_get,
353 .set = au_xattr_set
354 };
355
356 static const struct xattr_handler *au_xattr_handlers[] = {
357 #ifdef CONFIG_FS_POSIX_ACL
358 &posix_acl_access_xattr_handler,
359 &posix_acl_default_xattr_handler,
360 #endif
361 &au_xattr_handler, /* must be last */
362 NULL
363 };
364
365 void au_xattr_init(struct super_block *sb)
366 {
367 sb->s_xattr = au_xattr_handlers;
368 }