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