vfs_xattr.c revision 1.35.6.1 1 /* $NetBSD: vfs_xattr.c,v 1.35.6.1 2021/08/01 22:42:39 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1989, 1993
34 * The Regents of the University of California. All rights reserved.
35 * (c) UNIX System Laboratories, Inc.
36 * All or some portions of this file are derived from material licensed
37 * to the University of California by American Telephone and Telegraph
38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39 * the permission of UNIX System Laboratories, Inc.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66 /*
67 * VFS extended attribute support.
68 */
69
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: vfs_xattr.c,v 1.35.6.1 2021/08/01 22:42:39 thorpej Exp $");
72
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/namei.h>
76 #include <sys/filedesc.h>
77 #include <sys/kernel.h>
78 #include <sys/file.h>
79 #include <sys/vnode.h>
80 #include <sys/mount.h>
81 #include <sys/proc.h>
82 #include <sys/uio.h>
83 #include <sys/extattr.h>
84 #include <sys/xattr.h>
85 #include <sys/sysctl.h>
86 #include <sys/syscallargs.h>
87 #include <sys/kauth.h>
88 #include <sys/ktrace.h>
89
90 #include <miscfs/genfs/genfs.h>
91
92 static void
93 ktr_xattr_name(const char *str)
94 {
95 ktrkuser("xattr-name", (void *)__UNCONST(str), strlen(str));
96 }
97
98 static void
99 ktr_xattr_val(const void *data, size_t cnt)
100 {
101 ktruser("xattr-val", __UNCONST(data), cnt, 0);
102 }
103
104 /*
105 * Credential check based on process requesting service, and per-attribute
106 * permissions.
107 *
108 * NOTE: Vnode must be locked.
109 */
110 int
111 extattr_check_cred(struct vnode *vp, int attrspace, kauth_cred_t cred,
112 int access)
113 {
114
115 if (cred == NOCRED)
116 return (0);
117
118 return kauth_authorize_vnode(cred, kauth_extattr_action(access), vp,
119 NULL, genfs_can_extattr(vp, cred, access, attrspace));
120 }
121
122 /*
123 * Default vfs_extattrctl routine for file systems that do not support
124 * it.
125 */
126 /*ARGSUSED*/
127 int
128 vfs_stdextattrctl(struct mount *mp, int cmt, struct vnode *vp,
129 int attrnamespace, const char *attrname)
130 {
131
132 if (vp != NULL)
133 VOP_UNLOCK(vp);
134 return (EOPNOTSUPP);
135 }
136
137 /*
138 * Push extended attribute configuration information into the file
139 * system.
140 *
141 * NOTE: Not all file systems that support extended attributes will
142 * require the use of this system call.
143 */
144 int
145 sys_extattrctl(struct lwp *l, const struct sys_extattrctl_args *uap, register_t *retval)
146 {
147 /* {
148 syscallarg(const char *) path;
149 syscallarg(int) cmd;
150 syscallarg(const char *) filename;
151 syscallarg(int) attrnamespace;
152 syscallarg(const char *) attrname;
153 } */
154 struct vnode *path_vp, *file_vp;
155 struct pathbuf *file_pb;
156 struct nameidata file_nd;
157 char attrname[EXTATTR_MAXNAMELEN];
158 int error;
159
160 if (SCARG(uap, attrname) != NULL) {
161 error = copyinstr(SCARG(uap, attrname), attrname,
162 sizeof(attrname), NULL);
163 if (error)
164 return (error);
165 }
166
167 error = namei_simple_user(SCARG(uap, path),
168 NSM_FOLLOW_NOEMULROOT, &path_vp);
169 if (error) {
170 return (error);
171 }
172
173 file_vp = NULL;
174 if (SCARG(uap, filename) != NULL) {
175 error = pathbuf_copyin(SCARG(uap, filename), &file_pb);
176 if (error) {
177 vrele(path_vp);
178 return (error);
179 }
180 NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, file_pb);
181 error = namei(&file_nd);
182 if (error) {
183 pathbuf_destroy(file_pb);
184 vrele(path_vp);
185 return (error);
186 }
187 file_vp = file_nd.ni_vp;
188 pathbuf_destroy(file_pb);
189 }
190
191 error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp,
192 SCARG(uap, attrnamespace),
193 SCARG(uap, attrname) != NULL ? attrname : NULL);
194
195 if (file_vp != NULL)
196 vrele(file_vp);
197 vrele(path_vp);
198
199 return (error);
200 }
201
202 /*****************************************************************************
203 * Internal routines to manipulate file system extended attributes:
204 * - set
205 * - get
206 * - delete
207 * - list
208 *****************************************************************************/
209
210 /*
211 * extattr_set_vp:
212 *
213 * Set a named extended attribute on a file or directory.
214 */
215 static int
216 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
217 const void *data, size_t nbytes, struct lwp *l, register_t *retval,
218 int flag)
219 {
220 struct uio auio;
221 struct iovec aiov;
222 ssize_t cnt;
223 int error;
224
225 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
226
227 if (flag) {
228 size_t attrlen;
229
230 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL,
231 &attrlen, l->l_cred);
232
233 switch (error) {
234 case ENODATA:
235 if (flag & XATTR_REPLACE)
236 goto done;
237 break;
238 case 0:
239 if (flag & XATTR_CREATE) {
240 error = EEXIST;
241 goto done;
242 }
243 break;
244 default:
245 goto done;
246 break;
247 }
248 }
249
250 aiov.iov_base = __UNCONST(data); /* XXXUNCONST kills const */
251 aiov.iov_len = nbytes;
252 auio.uio_iov = &aiov;
253 auio.uio_iovcnt = 1;
254 auio.uio_offset = 0;
255 if (nbytes > INT_MAX) {
256 error = EINVAL;
257 goto done;
258 }
259 auio.uio_resid = nbytes;
260 auio.uio_rw = UIO_WRITE;
261 KASSERT(l == curlwp);
262 auio.uio_vmspace = l->l_proc->p_vmspace;
263 cnt = nbytes;
264
265 ktr_xattr_name(attrname);
266 ktr_xattr_val(data, nbytes);
267
268 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, l->l_cred);
269 cnt -= auio.uio_resid;
270 retval[0] = cnt;
271
272 done:
273 VOP_UNLOCK(vp);
274 return (error);
275 }
276
277 /*
278 * extattr_get_vp:
279 *
280 * Get a named extended attribute on a file or directory.
281 */
282 static int
283 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
284 void *data, size_t nbytes, struct lwp *l, register_t *retval)
285 {
286 struct uio auio, *auiop;
287 struct iovec aiov;
288 ssize_t cnt;
289 size_t size, *sizep;
290 int error;
291
292 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
293
294 /*
295 * Slightly unusual semantics: if the user provides a NULL data
296 * pointer, they don't want to receive the data, just the maximum
297 * read length.
298 */
299 auiop = NULL;
300 sizep = NULL;
301 cnt = 0;
302 if (data != NULL) {
303 aiov.iov_base = data;
304 aiov.iov_len = nbytes;
305 auio.uio_iov = &aiov;
306 auio.uio_offset = 0;
307 if (nbytes > INT_MAX) {
308 error = EINVAL;
309 goto done;
310 }
311 auio.uio_resid = nbytes;
312 auio.uio_rw = UIO_READ;
313 KASSERT(l == curlwp);
314 auio.uio_vmspace = l->l_proc->p_vmspace;
315 auiop = &auio;
316 cnt = nbytes;
317 } else
318 sizep = &size;
319
320 ktr_xattr_name(attrname);
321
322 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
323 l->l_cred);
324
325 if (auiop != NULL) {
326 cnt -= auio.uio_resid;
327 retval[0] = cnt;
328
329 ktr_xattr_val(data, cnt);
330 } else
331 retval[0] = size;
332
333 done:
334 VOP_UNLOCK(vp);
335 return (error);
336 }
337
338 /*
339 * extattr_delete_vp:
340 *
341 * Delete a named extended attribute on a file or directory.
342 */
343 static int
344 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
345 struct lwp *l)
346 {
347 int error;
348
349 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
350
351 ktr_xattr_name(attrname);
352
353 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, l->l_cred);
354 if (error == EOPNOTSUPP)
355 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
356 l->l_cred);
357
358 VOP_UNLOCK(vp);
359 return (error);
360 }
361
362 /*
363 * extattr_list_vp:
364 *
365 * Retrieve a list of extended attributes on a file or directory.
366 */
367 static int
368 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes,
369 int flag, struct lwp *l, register_t *retval)
370 {
371 struct uio auio, *auiop;
372 size_t size, *sizep;
373 struct iovec aiov;
374 ssize_t cnt;
375 int error;
376
377 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
378
379 auiop = NULL;
380 sizep = NULL;
381 cnt = 0;
382 if (data != NULL) {
383 aiov.iov_base = data;
384 aiov.iov_len = nbytes;
385 auio.uio_iov = &aiov;
386 auio.uio_offset = 0;
387 if (nbytes > INT_MAX) {
388 error = EINVAL;
389 goto done;
390 }
391 auio.uio_resid = nbytes;
392 auio.uio_rw = UIO_READ;
393 KASSERT(l == curlwp);
394 auio.uio_vmspace = l->l_proc->p_vmspace;
395 auiop = &auio;
396 cnt = nbytes;
397 } else
398 sizep = &size;
399
400 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
401 flag, l->l_cred);
402
403 if (auiop != NULL) {
404 cnt -= auio.uio_resid;
405 retval[0] = cnt;
406
407 ktruser("xattr-list", data, cnt, 0);
408 } else
409 retval[0] = size;
410
411 done:
412 VOP_UNLOCK(vp);
413 return (error);
414 }
415
416 /*****************************************************************************
417 * BSD <sys/extattr.h> API for file system extended attributes
418 *****************************************************************************/
419
420 int
421 sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, register_t *retval)
422 {
423 /* {
424 syscallarg(int) fd;
425 syscallarg(int) attrnamespace;
426 syscallarg(const char *) attrname;
427 syscallarg(const void *) data;
428 syscallarg(size_t) nbytes;
429 } */
430 struct file *fp;
431 struct vnode *vp;
432 char attrname[EXTATTR_MAXNAMELEN];
433 int error;
434
435 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
436 NULL);
437 if (error)
438 return (error);
439
440 error = fd_getvnode(SCARG(uap, fd), &fp);
441 if (error)
442 return (error);
443 vp = fp->f_vnode;
444
445 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
446 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
447
448 fd_putfile(SCARG(uap, fd));
449 return (error);
450 }
451
452 int
453 sys_extattr_set_file(struct lwp *l, const struct sys_extattr_set_file_args *uap, register_t *retval)
454 {
455 /* {
456 syscallarg(const char *) path;
457 syscallarg(int) attrnamespace;
458 syscallarg(const char *) attrname;
459 syscallarg(const void *) data;
460 syscallarg(size_t) nbytes;
461 } */
462 struct vnode *vp;
463 char attrname[EXTATTR_MAXNAMELEN];
464 int error;
465
466 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
467 NULL);
468 if (error)
469 return (error);
470
471 error = namei_simple_user(SCARG(uap, path),
472 NSM_FOLLOW_NOEMULROOT, &vp);
473 if (error)
474 return (error);
475
476 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
477 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
478
479 vrele(vp);
480 return (error);
481 }
482
483 int
484 sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval)
485 {
486 /* {
487 syscallarg(const char *) path;
488 syscallarg(int) attrnamespace;
489 syscallarg(const char *) attrname;
490 syscallarg(const void *) data;
491 syscallarg(size_t) nbytes;
492 } */
493 struct vnode *vp;
494 char attrname[EXTATTR_MAXNAMELEN];
495 int error;
496
497 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
498 NULL);
499 if (error)
500 return (error);
501
502 error = namei_simple_user(SCARG(uap, path),
503 NSM_NOFOLLOW_NOEMULROOT, &vp);
504 if (error)
505 return (error);
506
507 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
508 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
509
510 vrele(vp);
511 return (error);
512 }
513
514 int
515 sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval)
516 {
517 /* {
518 syscallarg(int) fd;
519 syscallarg(int) attrnamespace;
520 syscallarg(const char *) attrname;
521 syscallarg(void *) data;
522 syscallarg(size_t) nbytes;
523 } */
524 struct file *fp;
525 struct vnode *vp;
526 char attrname[EXTATTR_MAXNAMELEN];
527 int error;
528
529 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
530 NULL);
531 if (error)
532 return (error);
533
534 error = fd_getvnode(SCARG(uap, fd), &fp);
535 if (error)
536 return (error);
537 vp = fp->f_vnode;
538
539 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
540 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
541
542 fd_putfile(SCARG(uap, fd));
543 return (error);
544 }
545
546 int
547 sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval)
548 {
549 /* {
550 syscallarg(const char *) path;
551 syscallarg(int) attrnamespace;
552 syscallarg(const char *) attrname;
553 syscallarg(void *) data;
554 syscallarg(size_t) nbytes;
555 } */
556 struct vnode *vp;
557 char attrname[EXTATTR_MAXNAMELEN];
558 int error;
559
560 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
561 NULL);
562 if (error)
563 return (error);
564
565 error = namei_simple_user(SCARG(uap, path),
566 NSM_FOLLOW_NOEMULROOT, &vp);
567 if (error)
568 return (error);
569
570 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
571 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
572
573 vrele(vp);
574 return (error);
575 }
576
577 int
578 sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval)
579 {
580 /* {
581 syscallarg(const char *) path;
582 syscallarg(int) attrnamespace;
583 syscallarg(const char *) attrname;
584 syscallarg(void *) data;
585 syscallarg(size_t) nbytes;
586 } */
587 struct vnode *vp;
588 char attrname[EXTATTR_MAXNAMELEN];
589 int error;
590
591 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
592 NULL);
593 if (error)
594 return (error);
595
596 error = namei_simple_user(SCARG(uap, path),
597 NSM_NOFOLLOW_NOEMULROOT, &vp);
598 if (error)
599 return (error);
600
601 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
602 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
603
604 vrele(vp);
605 return (error);
606 }
607
608 int
609 sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval)
610 {
611 /* {
612 syscallarg(int) fd;
613 syscallarg(int) attrnamespace;
614 syscallarg(const char *) attrname;
615 } */
616 struct file *fp;
617 struct vnode *vp;
618 char attrname[EXTATTR_MAXNAMELEN];
619 int error;
620
621 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
622 NULL);
623 if (error)
624 return (error);
625
626 error = fd_getvnode(SCARG(uap, fd), &fp);
627 if (error)
628 return (error);
629 vp = fp->f_vnode;
630
631 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
632
633 fd_putfile(SCARG(uap, fd));
634 return (error);
635 }
636
637 int
638 sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval)
639 {
640 /* {
641 syscallarg(const char *) path;
642 syscallarg(int) attrnamespace;
643 syscallarg(const char *) attrname;
644 } */
645 struct vnode *vp;
646 char attrname[EXTATTR_MAXNAMELEN];
647 int error;
648
649 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
650 NULL);
651 if (error)
652 return (error);
653
654 error = namei_simple_user(SCARG(uap, path),
655 NSM_FOLLOW_NOEMULROOT, &vp);
656 if (error)
657 return (error);
658
659 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
660
661 vrele(vp);
662 return (error);
663 }
664
665 int
666 sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval)
667 {
668 /* {
669 syscallarg(const char *) path;
670 syscallarg(int) attrnamespace;
671 syscallarg(const char *) attrname;
672 } */
673 struct vnode *vp;
674 char attrname[EXTATTR_MAXNAMELEN];
675 int error;
676
677 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
678 NULL);
679 if (error)
680 return (error);
681
682 error = namei_simple_user(SCARG(uap, path),
683 NSM_NOFOLLOW_NOEMULROOT, &vp);
684 if (error)
685 return (error);
686
687 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
688
689 vrele(vp);
690 return (error);
691 }
692
693 int
694 sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval)
695 {
696 /* {
697 syscallarg(int) fd;
698 syscallarg(int) attrnamespace;
699 syscallarg(void *) data;
700 syscallarg(size_t) nbytes;
701 } */
702 struct file *fp;
703 struct vnode *vp;
704 int error;
705
706 error = fd_getvnode(SCARG(uap, fd), &fp);
707 if (error)
708 return (error);
709 vp = fp->f_vnode;
710
711 error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
712 SCARG(uap, data), SCARG(uap, nbytes),
713 EXTATTR_LIST_LENPREFIX, l, retval);
714
715 fd_putfile(SCARG(uap, fd));
716 return (error);
717 }
718
719 int
720 sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval)
721 {
722 /* {
723 syscallarg(const char *) path;
724 syscallarg(int) attrnamespace;
725 syscallarg(void *) data;
726 syscallarg(size_t) nbytes;
727 } */
728 struct vnode *vp;
729 int error;
730
731 error = namei_simple_user(SCARG(uap, path),
732 NSM_FOLLOW_NOEMULROOT, &vp);
733 if (error)
734 return (error);
735
736 error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
737 SCARG(uap, data), SCARG(uap, nbytes),
738 EXTATTR_LIST_LENPREFIX, l, retval);
739
740 vrele(vp);
741 return (error);
742 }
743
744 int
745 sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval)
746 {
747 /* {
748 syscallarg(const char *) path;
749 syscallarg(int) attrnamespace;
750 syscallarg(void *) data;
751 syscallarg(size_t) nbytes;
752 } */
753 struct vnode *vp;
754 int error;
755
756 error = namei_simple_user(SCARG(uap, path),
757 NSM_NOFOLLOW_NOEMULROOT, &vp);
758 if (error)
759 return (error);
760
761 error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
762 SCARG(uap, data), SCARG(uap, nbytes),
763 EXTATTR_LIST_LENPREFIX, l, retval);
764
765 vrele(vp);
766 return (error);
767 }
768
769 /*****************************************************************************
770 * Linux-compatible <sys/xattr.h> API for file system extended attributes
771 *****************************************************************************/
772
773 #define MATCH_NS(ns, key) (strncmp(ns, key, sizeof(ns) - 1) == 0)
774 static int
775 xattr_native(const char *key) {
776 if (MATCH_NS("system.", key))
777 return EXTATTR_NAMESPACE_SYSTEM;
778 else if (MATCH_NS("user.", key))
779 return EXTATTR_NAMESPACE_USER;
780 else if (MATCH_NS("security.", key))
781 return EXTATTR_NAMESPACE_SYSTEM;
782 else if (MATCH_NS("trusted.", key))
783 return EXTATTR_NAMESPACE_SYSTEM;
784 else
785 return EXTATTR_NAMESPACE_USER;
786
787 }
788 #undef MATCH_NS
789
790 #define XATTR_ERRNO(e) ((e) == EOPNOTSUPP ? ENOTSUP : (e))
791
792 int
793 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval)
794 {
795 /* {
796 syscallarg(const char *) path;
797 syscallarg(const char *) name;
798 syscallarg(void *) value;
799 syscallarg(size_t) size;
800 syscallarg(int) flags;
801 } */
802 struct vnode *vp;
803 char attrname[XATTR_NAME_MAX];
804 int attrnamespace;
805 register_t attrlen;
806 int error;
807
808 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
809 NULL);
810 if (error)
811 goto out;
812
813 error = namei_simple_user(SCARG(uap, path),
814 NSM_FOLLOW_NOEMULROOT, &vp);
815 if (error)
816 goto out;
817
818 attrnamespace = xattr_native(attrname);
819
820 error = extattr_set_vp(vp, attrnamespace,
821 attrname, SCARG(uap, value), SCARG(uap, size), l,
822 &attrlen, SCARG(uap, flags));
823
824 vrele(vp);
825 out:
826 *retval = (error == 0) ? 0 : -1;
827 return (XATTR_ERRNO(error));
828 }
829
830 int
831 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval)
832 {
833 /* {
834 syscallarg(const char *) path;
835 syscallarg(const char *) name;
836 syscallarg(void *) value;
837 syscallarg(size_t) size;
838 syscallarg(int) flags;
839 } */
840 struct vnode *vp;
841 char attrname[XATTR_NAME_MAX];
842 int attrnamespace;
843 register_t attrlen;
844 int error;
845
846 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
847 NULL);
848 if (error)
849 goto out;
850
851 error = namei_simple_user(SCARG(uap, path),
852 NSM_NOFOLLOW_NOEMULROOT, &vp);
853 if (error)
854 goto out;
855
856 attrnamespace = xattr_native(attrname);
857
858 error = extattr_set_vp(vp, attrnamespace,
859 attrname, SCARG(uap, value), SCARG(uap, size), l,
860 &attrlen, SCARG(uap, flags));
861
862 vrele(vp);
863 out:
864 *retval = (error == 0) ? 0 : -1;
865 return (XATTR_ERRNO(error));
866 }
867
868 int
869 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval)
870 {
871 /* {
872 syscallarg(int) fd;
873 syscallarg(const char *) name;
874 syscallarg(void *) value;
875 syscallarg(size_t) size;
876 syscallarg(int) flags;
877 } */
878 struct file *fp;
879 struct vnode *vp;
880 char attrname[XATTR_NAME_MAX];
881 int attrnamespace;
882 register_t attrlen;
883 int error;
884
885 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
886 NULL);
887 if (error)
888 goto out;
889
890 error = fd_getvnode(SCARG(uap, fd), &fp);
891 if (error)
892 goto out;
893 vp = fp->f_vnode;
894
895 attrnamespace = xattr_native(attrname);
896
897 error = extattr_set_vp(vp, attrnamespace,
898 attrname, SCARG(uap, value), SCARG(uap, size), l,
899 &attrlen, SCARG(uap, flags));
900
901 fd_putfile(SCARG(uap, fd));
902 out:
903 *retval = (error == 0) ? 0 : -1;
904 return (XATTR_ERRNO(error));
905 }
906
907 int
908 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval)
909 {
910 /* {
911 syscallarg(const char *) path;
912 syscallarg(const char *) name;
913 syscallarg(void *) value;
914 syscallarg(size_t) size;
915 } */
916 struct vnode *vp;
917 char attrname[XATTR_NAME_MAX];
918 int attrnamespace;
919 int error;
920
921 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
922 NULL);
923 if (error)
924 return (error);
925
926 error = namei_simple_user(SCARG(uap, path),
927 NSM_FOLLOW_NOEMULROOT, &vp);
928 if (error)
929 return (error);
930
931 attrnamespace = xattr_native(attrname);
932
933 error = extattr_get_vp(vp, attrnamespace,
934 attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
935
936 vrele(vp);
937 return (XATTR_ERRNO(error));
938 }
939
940 int
941 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval)
942 {
943 /* {
944 syscallarg(const char *) path;
945 syscallarg(const char *) name;
946 syscallarg(void *) value;
947 syscallarg(size_t) size;
948 } */
949 struct vnode *vp;
950 char attrname[XATTR_NAME_MAX];
951 int attrnamespace;
952 int error;
953
954 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
955 NULL);
956 if (error)
957 return (error);
958
959 error = namei_simple_user(SCARG(uap, path),
960 NSM_NOFOLLOW_NOEMULROOT, &vp);
961 if (error)
962 return (error);
963
964 attrnamespace = xattr_native(attrname);
965
966 error = extattr_get_vp(vp, attrnamespace,
967 attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
968
969 vrele(vp);
970 return (XATTR_ERRNO(error));
971 }
972
973 int
974 sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval)
975 {
976 /* {
977 syscallarg(int) fd;
978 syscallarg(const char *) name;
979 syscallarg(void *) value;
980 syscallarg(size_t) size;
981 } */
982 struct file *fp;
983 struct vnode *vp;
984 char attrname[XATTR_NAME_MAX];
985 int attrnamespace;
986 int error;
987
988 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
989 NULL);
990 if (error)
991 return (error);
992
993 error = fd_getvnode(SCARG(uap, fd), &fp);
994 if (error)
995 return (error);
996 vp = fp->f_vnode;
997
998 attrnamespace = xattr_native(attrname);
999
1000 error = extattr_get_vp(vp, attrnamespace,
1001 attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
1002
1003 fd_putfile(SCARG(uap, fd));
1004 return (XATTR_ERRNO(error));
1005 }
1006
1007 int
1008 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval)
1009 {
1010 /* {
1011 syscallarg(const char *) path;
1012 syscallarg(char *) list;
1013 syscallarg(size_t) size;
1014 } */
1015 struct vnode *vp;
1016 char *list;
1017 size_t size;
1018 register_t listsize_usr, listsize_sys;
1019 int error;
1020
1021 error = namei_simple_user(SCARG(uap, path),
1022 NSM_FOLLOW_NOEMULROOT, &vp);
1023 if (error)
1024 return (error);
1025
1026 list = SCARG(uap, list);
1027 size = SCARG(uap, size);
1028
1029 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1030 list, size, 0, l, &listsize_usr);
1031 if (error)
1032 goto out;
1033
1034 if (list)
1035 list += listsize_usr;
1036 if (size)
1037 size -= listsize_usr;
1038
1039 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1040 list, size, 0, l, &listsize_sys);
1041 switch (error) {
1042 case EPERM:
1043 error = 0; /* Ignore and just skip system EA */
1044 listsize_sys = 0;
1045 break;
1046 case 0:
1047 break;
1048 default:
1049 goto out;
1050 break;
1051 }
1052
1053 *retval = listsize_usr + listsize_sys;
1054
1055 out:
1056 vrele(vp);
1057 return (XATTR_ERRNO(error));
1058 }
1059
1060 int
1061 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval)
1062 {
1063 /* {
1064 syscallarg(const char *) path;
1065 syscallarg(char *) list;
1066 syscallarg(size_t) size;
1067 } */
1068 struct vnode *vp;
1069 char *list;
1070 size_t size;
1071 register_t listsize_usr, listsize_sys;
1072 int error;
1073
1074 error = namei_simple_user(SCARG(uap, path),
1075 NSM_NOFOLLOW_NOEMULROOT, &vp);
1076 if (error)
1077 return (error);
1078
1079 list = SCARG(uap, list);
1080 size = SCARG(uap, size);
1081
1082 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1083 list, size, 0, l, &listsize_usr);
1084 if (error)
1085 goto out;
1086 if (list)
1087 list += listsize_usr;
1088 if (size)
1089 size -= listsize_usr;
1090
1091 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1092 list, size, 0, l, &listsize_sys);
1093 switch (error) {
1094 case EPERM:
1095 error = 0; /* Ignore and just skip system EA */
1096 listsize_sys = 0;
1097 break;
1098 case 0:
1099 break;
1100 default:
1101 goto out;
1102 break;
1103 }
1104
1105 *retval = listsize_usr + listsize_sys;
1106 out:
1107 vrele(vp);
1108 return (XATTR_ERRNO(error));
1109 }
1110
1111 int
1112 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval)
1113 {
1114 /* {
1115 syscallarg(int) fd;
1116 syscallarg(char *) list;
1117 syscallarg(size_t) size;
1118 } */
1119 struct file *fp;
1120 struct vnode *vp;
1121 char *list;
1122 size_t size;
1123 register_t listsize_usr, listsize_sys;
1124 int error;
1125
1126 error = fd_getvnode(SCARG(uap, fd), &fp);
1127 if (error)
1128 return (error);
1129 vp = fp->f_vnode;
1130
1131 list = SCARG(uap, list);
1132 size = SCARG(uap, size);
1133
1134 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1135 list, size, 0, l, &listsize_usr);
1136 if (error)
1137 goto out;
1138
1139 if (list)
1140 list += listsize_usr;
1141 if (size)
1142 size -= listsize_usr;
1143
1144 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1145 list, size, 0, l, &listsize_sys);
1146 switch (error) {
1147 case EPERM:
1148 error = 0; /* Ignore and just skip system EA */
1149 listsize_sys = 0;
1150 break;
1151 case 0:
1152 break;
1153 default:
1154 goto out;
1155 break;
1156 }
1157
1158 *retval = listsize_usr + listsize_sys;
1159 out:
1160
1161 fd_putfile(SCARG(uap, fd));
1162 return (XATTR_ERRNO(error));
1163 }
1164
1165 int
1166 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval)
1167 {
1168 /* {
1169 syscallarg(const char *) path;
1170 syscallarg(const char *) name;
1171 } */
1172 struct vnode *vp;
1173 char attrname[XATTR_NAME_MAX];
1174 int attrnamespace;
1175 int error;
1176
1177 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1178 NULL);
1179 if (error)
1180 return (error);
1181
1182 error = namei_simple_user(SCARG(uap, path),
1183 NSM_FOLLOW_NOEMULROOT, &vp);
1184 if (error)
1185 return (error);
1186
1187 attrnamespace = xattr_native(attrname);
1188
1189 error = extattr_delete_vp(vp, attrnamespace, attrname, l);
1190
1191 vrele(vp);
1192 return (XATTR_ERRNO(error));
1193 }
1194
1195 int
1196 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval)
1197 {
1198 /* {
1199 syscallarg(const char *) path;
1200 syscallarg(const char *) name;
1201 } */
1202 struct vnode *vp;
1203 char attrname[XATTR_NAME_MAX];
1204 int attrnamespace;
1205 int error;
1206
1207 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1208 NULL);
1209 if (error)
1210 return (error);
1211
1212 error = namei_simple_user(SCARG(uap, path),
1213 NSM_NOFOLLOW_NOEMULROOT, &vp);
1214 if (error)
1215 return (error);
1216
1217 attrnamespace = xattr_native(attrname);
1218
1219 error = extattr_delete_vp(vp, attrnamespace, attrname, l);
1220
1221 vrele(vp);
1222 return (XATTR_ERRNO(error));
1223 }
1224
1225 int
1226 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval)
1227 {
1228 /* {
1229 syscallarg(int) fd;
1230 syscallarg(const char *) name;
1231 } */
1232 struct file *fp;
1233 struct vnode *vp;
1234 char attrname[XATTR_NAME_MAX];
1235 int attrnamespace;
1236 int error;
1237
1238 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1239 NULL);
1240 if (error)
1241 return (error);
1242
1243 error = fd_getvnode(SCARG(uap, fd), &fp);
1244 if (error)
1245 return (error);
1246 vp = fp->f_vnode;
1247
1248 attrnamespace = xattr_native(attrname);
1249
1250 error = extattr_delete_vp(vp, attrnamespace, attrname, l);
1251
1252 fd_putfile(SCARG(uap, fd));
1253 return (XATTR_ERRNO(error));
1254 }
1255