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