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