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