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