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