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