xref: /netbsd-src/sys/kern/vfs_xattr.c (revision aef5eb5f59cdfe8314f1b5f78ac04eb144e44010)
1 /*	$NetBSD: vfs_xattr.c,v 1.36 2021/06/27 09:13:08 christos 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.36 2021/06/27 09:13:08 christos 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