Home | History | Annotate | Line # | Download | only in kern
vfs_xattr.c revision 1.37
      1 /*	$NetBSD: vfs_xattr.c,v 1.37 2022/10/25 23:22:17 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.37 2022/10/25 23:22:17 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),
    168 				NSM_FOLLOW_NOEMULROOT, &path_vp);
    169 	if (error) {
    170 		return (error);
    171 	}
    172 
    173 	file_vp = NULL;
    174 	if (SCARG(uap, filename) != NULL) {
    175 		error = pathbuf_copyin(SCARG(uap, filename), &file_pb);
    176 		if (error) {
    177 			vrele(path_vp);
    178 			return (error);
    179 		}
    180 		NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, file_pb);
    181 		error = namei(&file_nd);
    182 		if (error) {
    183 			pathbuf_destroy(file_pb);
    184 			vrele(path_vp);
    185 			return (error);
    186 		}
    187 		file_vp = file_nd.ni_vp;
    188 		pathbuf_destroy(file_pb);
    189 	}
    190 
    191 	error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp,
    192 	    SCARG(uap, attrnamespace),
    193 	    SCARG(uap, attrname) != NULL ? attrname : NULL);
    194 
    195 	if (file_vp != NULL)
    196 		vrele(file_vp);
    197 	vrele(path_vp);
    198 
    199 	return (error);
    200 }
    201 
    202 /*****************************************************************************
    203  * Internal routines to manipulate file system extended attributes:
    204  *	- set
    205  *	- get
    206  *	- delete
    207  *	- list
    208  *****************************************************************************/
    209 
    210 /*
    211  * extattr_set_vp:
    212  *
    213  *	Set a named extended attribute on a file or directory.
    214  */
    215 static int
    216 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
    217     const void *data, size_t nbytes, struct lwp *l, register_t *retval,
    218     int flag)
    219 {
    220 	struct uio auio;
    221 	struct iovec aiov;
    222 	ssize_t cnt;
    223 	int error;
    224 
    225 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    226 
    227 	if (flag) {
    228 		size_t attrlen;
    229 
    230 		error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL,
    231 				       &attrlen, l->l_cred);
    232 
    233 		switch (error) {
    234 		case ENODATA:
    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,
    403 				flag, 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, 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, const struct sys_extattr_set_file_args *uap, register_t *retval)
    456 {
    457 	/* {
    458 		syscallarg(const char *) path;
    459 		syscallarg(int) attrnamespace;
    460 		syscallarg(const char *) attrname;
    461 		syscallarg(const void *) data;
    462 		syscallarg(size_t) nbytes;
    463 	} */
    464 	struct vnode *vp;
    465 	char attrname[EXTATTR_MAXNAMELEN];
    466 	int error;
    467 
    468 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    469 	    NULL);
    470 	if (error)
    471 		return (error);
    472 
    473 	error = namei_simple_user(SCARG(uap, path),
    474 				NSM_FOLLOW_NOEMULROOT, &vp);
    475 	if (error)
    476 		return (error);
    477 
    478 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
    479 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
    480 
    481 	vrele(vp);
    482 	return (error);
    483 }
    484 
    485 int
    486 sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval)
    487 {
    488 	/* {
    489 		syscallarg(const char *) path;
    490 		syscallarg(int) attrnamespace;
    491 		syscallarg(const char *) attrname;
    492 		syscallarg(const void *) data;
    493 		syscallarg(size_t) nbytes;
    494 	} */
    495 	struct vnode *vp;
    496 	char attrname[EXTATTR_MAXNAMELEN];
    497 	int error;
    498 
    499 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    500 	    NULL);
    501 	if (error)
    502 		return (error);
    503 
    504 	error = namei_simple_user(SCARG(uap, path),
    505 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    506 	if (error)
    507 		return (error);
    508 
    509 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
    510 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
    511 
    512 	vrele(vp);
    513 	return (error);
    514 }
    515 
    516 int
    517 sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval)
    518 {
    519 	/* {
    520 		syscallarg(int) fd;
    521 		syscallarg(int) attrnamespace;
    522 		syscallarg(const char *) attrname;
    523 		syscallarg(void *) data;
    524 		syscallarg(size_t) nbytes;
    525 	} */
    526 	struct file *fp;
    527 	struct vnode *vp;
    528 	char attrname[EXTATTR_MAXNAMELEN];
    529 	int error;
    530 
    531 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    532 	    NULL);
    533 	if (error)
    534 		return (error);
    535 
    536 	error = fd_getvnode(SCARG(uap, fd), &fp);
    537 	if (error)
    538 		return (error);
    539 	vp = fp->f_vnode;
    540 
    541 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    542 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    543 
    544 	fd_putfile(SCARG(uap, fd));
    545 	return (error);
    546 }
    547 
    548 int
    549 sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval)
    550 {
    551 	/* {
    552 		syscallarg(const char *) path;
    553 		syscallarg(int) attrnamespace;
    554 		syscallarg(const char *) attrname;
    555 		syscallarg(void *) data;
    556 		syscallarg(size_t) nbytes;
    557 	} */
    558 	struct vnode *vp;
    559 	char attrname[EXTATTR_MAXNAMELEN];
    560 	int error;
    561 
    562 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    563 	    NULL);
    564 	if (error)
    565 		return (error);
    566 
    567 	error = namei_simple_user(SCARG(uap, path),
    568 				NSM_FOLLOW_NOEMULROOT, &vp);
    569 	if (error)
    570 		return (error);
    571 
    572 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    573 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    574 
    575 	vrele(vp);
    576 	return (error);
    577 }
    578 
    579 int
    580 sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval)
    581 {
    582 	/* {
    583 		syscallarg(const char *) path;
    584 		syscallarg(int) attrnamespace;
    585 		syscallarg(const char *) attrname;
    586 		syscallarg(void *) data;
    587 		syscallarg(size_t) nbytes;
    588 	} */
    589 	struct vnode *vp;
    590 	char attrname[EXTATTR_MAXNAMELEN];
    591 	int error;
    592 
    593 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    594 	    NULL);
    595 	if (error)
    596 		return (error);
    597 
    598 	error = namei_simple_user(SCARG(uap, path),
    599 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    600 	if (error)
    601 		return (error);
    602 
    603 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    604 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    605 
    606 	vrele(vp);
    607 	return (error);
    608 }
    609 
    610 int
    611 sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval)
    612 {
    613 	/* {
    614 		syscallarg(int) fd;
    615 		syscallarg(int) attrnamespace;
    616 		syscallarg(const char *) attrname;
    617 	} */
    618 	struct file *fp;
    619 	struct vnode *vp;
    620 	char attrname[EXTATTR_MAXNAMELEN];
    621 	int error;
    622 
    623 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    624 	    NULL);
    625 	if (error)
    626 		return (error);
    627 
    628 	error = fd_getvnode(SCARG(uap, fd), &fp);
    629 	if (error)
    630 		return (error);
    631 	vp = fp->f_vnode;
    632 
    633 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    634 
    635 	fd_putfile(SCARG(uap, fd));
    636 	return (error);
    637 }
    638 
    639 int
    640 sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval)
    641 {
    642 	/* {
    643 		syscallarg(const char *) path;
    644 		syscallarg(int) attrnamespace;
    645 		syscallarg(const char *) attrname;
    646 	} */
    647 	struct vnode *vp;
    648 	char attrname[EXTATTR_MAXNAMELEN];
    649 	int error;
    650 
    651 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    652 	    NULL);
    653 	if (error)
    654 		return (error);
    655 
    656 	error = namei_simple_user(SCARG(uap, path),
    657 				NSM_FOLLOW_NOEMULROOT, &vp);
    658 	if (error)
    659 		return (error);
    660 
    661 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    662 
    663 	vrele(vp);
    664 	return (error);
    665 }
    666 
    667 int
    668 sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval)
    669 {
    670 	/* {
    671 		syscallarg(const char *) path;
    672 		syscallarg(int) attrnamespace;
    673 		syscallarg(const char *) attrname;
    674 	} */
    675 	struct vnode *vp;
    676 	char attrname[EXTATTR_MAXNAMELEN];
    677 	int error;
    678 
    679 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    680 	    NULL);
    681 	if (error)
    682 		return (error);
    683 
    684 	error = namei_simple_user(SCARG(uap, path),
    685 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    686 	if (error)
    687 		return (error);
    688 
    689 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    690 
    691 	vrele(vp);
    692 	return (error);
    693 }
    694 
    695 int
    696 sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval)
    697 {
    698 	/* {
    699 		syscallarg(int) fd;
    700 		syscallarg(int) attrnamespace;
    701 		syscallarg(void *) data;
    702 		syscallarg(size_t) nbytes;
    703 	} */
    704 	struct file *fp;
    705 	struct vnode *vp;
    706 	int error;
    707 
    708 	error = fd_getvnode(SCARG(uap, fd), &fp);
    709 	if (error)
    710 		return (error);
    711 	vp = fp->f_vnode;
    712 
    713 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    714 	    SCARG(uap, data), SCARG(uap, nbytes),
    715 	    EXTATTR_LIST_LENPREFIX, l, retval);
    716 
    717 	fd_putfile(SCARG(uap, fd));
    718 	return (error);
    719 }
    720 
    721 int
    722 sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval)
    723 {
    724 	/* {
    725 		syscallarg(const char *) path;
    726 		syscallarg(int) attrnamespace;
    727 		syscallarg(void *) data;
    728 		syscallarg(size_t) nbytes;
    729 	} */
    730 	struct vnode *vp;
    731 	int error;
    732 
    733 	error = namei_simple_user(SCARG(uap, path),
    734 				NSM_FOLLOW_NOEMULROOT, &vp);
    735 	if (error)
    736 		return (error);
    737 
    738 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    739 	    SCARG(uap, data), SCARG(uap, nbytes),
    740 	    EXTATTR_LIST_LENPREFIX, l, retval);
    741 
    742 	vrele(vp);
    743 	return (error);
    744 }
    745 
    746 int
    747 sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval)
    748 {
    749 	/* {
    750 		syscallarg(const char *) path;
    751 		syscallarg(int) attrnamespace;
    752 		syscallarg(void *) data;
    753 		syscallarg(size_t) nbytes;
    754 	} */
    755 	struct vnode *vp;
    756 	int error;
    757 
    758 	error = namei_simple_user(SCARG(uap, path),
    759 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    760 	if (error)
    761 		return (error);
    762 
    763 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    764 	    SCARG(uap, data), SCARG(uap, nbytes),
    765 	    EXTATTR_LIST_LENPREFIX, l, retval);
    766 
    767 	vrele(vp);
    768 	return (error);
    769 }
    770 
    771 /*****************************************************************************
    772  * Linux-compatible <sys/xattr.h> API for file system extended attributes
    773  *****************************************************************************/
    774 
    775 #define MATCH_NS(ns, key) (strncmp(ns, key, sizeof(ns) - 1) == 0)
    776 static int
    777 xattr_native(const char *key) {
    778 	if (MATCH_NS("system.", key))
    779 		return EXTATTR_NAMESPACE_SYSTEM;
    780 	else if (MATCH_NS("user.", key))
    781 		return EXTATTR_NAMESPACE_USER;
    782 	else if (MATCH_NS("security.", key))
    783 		return EXTATTR_NAMESPACE_SYSTEM;
    784 	else if (MATCH_NS("trusted.", key))
    785 		return EXTATTR_NAMESPACE_SYSTEM;
    786 	else
    787 		return EXTATTR_NAMESPACE_USER;
    788 
    789 }
    790 #undef MATCH_NS
    791 
    792 #define XATTR_ERRNO(e) ((e) == EOPNOTSUPP ? ENOTSUP : (e))
    793 
    794 int
    795 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval)
    796 {
    797 	/* {
    798 		syscallarg(const char *) path;
    799 		syscallarg(const char *) name;
    800 		syscallarg(void *) value;
    801 		syscallarg(size_t) size;
    802 		syscallarg(int) flags;
    803 	} */
    804 	struct vnode *vp;
    805 	char attrname[XATTR_NAME_MAX];
    806 	int attrnamespace;
    807 	register_t attrlen;
    808 	int error;
    809 
    810 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    811 	    NULL);
    812 	if (error)
    813 		goto out;
    814 
    815 	error = namei_simple_user(SCARG(uap, path),
    816 				NSM_FOLLOW_NOEMULROOT, &vp);
    817 	if (error)
    818 		goto out;
    819 
    820 	attrnamespace = xattr_native(attrname);
    821 
    822 	error = extattr_set_vp(vp, attrnamespace,
    823 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
    824 	    &attrlen, SCARG(uap, flags));
    825 
    826 	vrele(vp);
    827 out:
    828 	*retval = (error == 0) ? 0 : -1;
    829 	return (XATTR_ERRNO(error));
    830 }
    831 
    832 int
    833 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval)
    834 {
    835 	/* {
    836 		syscallarg(const char *) path;
    837 		syscallarg(const char *) name;
    838 		syscallarg(void *) value;
    839 		syscallarg(size_t) size;
    840 		syscallarg(int) flags;
    841 	} */
    842 	struct vnode *vp;
    843 	char attrname[XATTR_NAME_MAX];
    844 	int attrnamespace;
    845 	register_t attrlen;
    846 	int error;
    847 
    848 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    849 	    NULL);
    850 	if (error)
    851 		goto out;
    852 
    853 	error = namei_simple_user(SCARG(uap, path),
    854 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    855 	if (error)
    856 		goto out;
    857 
    858 	attrnamespace = xattr_native(attrname);
    859 
    860 	error = extattr_set_vp(vp, attrnamespace,
    861 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
    862 	    &attrlen, SCARG(uap, flags));
    863 
    864 	vrele(vp);
    865 out:
    866 	*retval = (error == 0) ? 0 : -1;
    867 	return (XATTR_ERRNO(error));
    868 }
    869 
    870 int
    871 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval)
    872 {
    873 	/* {
    874 		syscallarg(int) fd;
    875 		syscallarg(const char *) name;
    876 		syscallarg(void *) value;
    877 		syscallarg(size_t) size;
    878 		syscallarg(int) flags;
    879 	} */
    880 	struct file *fp;
    881 	struct vnode *vp;
    882 	char attrname[XATTR_NAME_MAX];
    883 	int attrnamespace;
    884 	register_t attrlen;
    885 	int error;
    886 
    887 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    888 	    NULL);
    889 	if (error)
    890 		goto out;
    891 
    892 	error = fd_getvnode(SCARG(uap, fd), &fp);
    893 	if (error)
    894 		goto out;
    895 	vp = fp->f_vnode;
    896 
    897 	attrnamespace = xattr_native(attrname);
    898 
    899 	error = extattr_set_vp(vp, attrnamespace,
    900 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
    901 	    &attrlen, SCARG(uap, flags));
    902 
    903 	fd_putfile(SCARG(uap, fd));
    904 out:
    905 	*retval = (error == 0) ? 0 : -1;
    906 	return (XATTR_ERRNO(error));
    907 }
    908 
    909 int
    910 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval)
    911 {
    912 	/* {
    913 		syscallarg(const char *) path;
    914 		syscallarg(const char *) name;
    915 		syscallarg(void *) value;
    916 		syscallarg(size_t) size;
    917 	} */
    918 	struct vnode *vp;
    919 	char attrname[XATTR_NAME_MAX];
    920 	int attrnamespace;
    921 	int error;
    922 
    923 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    924 	    NULL);
    925 	if (error)
    926 		return (error);
    927 
    928 	error = namei_simple_user(SCARG(uap, path),
    929 				NSM_FOLLOW_NOEMULROOT, &vp);
    930 	if (error)
    931 		return (error);
    932 
    933 	attrnamespace = xattr_native(attrname);
    934 
    935 	error = extattr_get_vp(vp, attrnamespace,
    936 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    937 
    938 	vrele(vp);
    939 	return (XATTR_ERRNO(error));
    940 }
    941 
    942 int
    943 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval)
    944 {
    945 	/* {
    946 		syscallarg(const char *) path;
    947 		syscallarg(const char *) name;
    948 		syscallarg(void *) value;
    949 		syscallarg(size_t) size;
    950 	} */
    951 	struct vnode *vp;
    952 	char attrname[XATTR_NAME_MAX];
    953 	int attrnamespace;
    954 	int error;
    955 
    956 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    957 	    NULL);
    958 	if (error)
    959 		return (error);
    960 
    961 	error = namei_simple_user(SCARG(uap, path),
    962 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    963 	if (error)
    964 		return (error);
    965 
    966 	attrnamespace = xattr_native(attrname);
    967 
    968 	error = extattr_get_vp(vp, attrnamespace,
    969 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    970 
    971 	vrele(vp);
    972 	return (XATTR_ERRNO(error));
    973 }
    974 
    975 int
    976 sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval)
    977 {
    978 	/* {
    979 		syscallarg(int) fd;
    980 		syscallarg(const char *) name;
    981 		syscallarg(void *) value;
    982 		syscallarg(size_t) size;
    983 	} */
    984 	struct file *fp;
    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 = fd_getvnode(SCARG(uap, fd), &fp);
    996 	if (error)
    997 		return (error);
    998 	vp = fp->f_vnode;
    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 	fd_putfile(SCARG(uap, fd));
   1006 	return (XATTR_ERRNO(error));
   1007 }
   1008 
   1009 int
   1010 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval)
   1011 {
   1012 	/* {
   1013 		syscallarg(const char *) path;
   1014 		syscallarg(char *) list;
   1015 		syscallarg(size_t) size;
   1016 	} */
   1017 	struct vnode *vp;
   1018 	char *list;
   1019 	size_t size;
   1020 	register_t listsize_usr, listsize_sys;
   1021 	int error;
   1022 
   1023 	error = namei_simple_user(SCARG(uap, path),
   1024 				NSM_FOLLOW_NOEMULROOT, &vp);
   1025 	if (error)
   1026 		return (error);
   1027 
   1028 	list = SCARG(uap, list);
   1029 	size = SCARG(uap, size);
   1030 
   1031 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
   1032 	    list, size, 0, l, &listsize_usr);
   1033 	if (error)
   1034 		goto out;
   1035 
   1036 	if (list)
   1037 		list += listsize_usr;
   1038 	if (size)
   1039 		size -= listsize_usr;
   1040 
   1041 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
   1042 	    list, size, 0, l, &listsize_sys);
   1043 	switch (error) {
   1044 	case EPERM:
   1045 		error = 0; /* Ignore and just skip system EA */
   1046 		listsize_sys = 0;
   1047 		break;
   1048 	case 0:
   1049 		break;
   1050 	default:
   1051 		goto out;
   1052 		break;
   1053 	}
   1054 
   1055 	*retval = listsize_usr + listsize_sys;
   1056 
   1057 out:
   1058 	vrele(vp);
   1059 	return (XATTR_ERRNO(error));
   1060 }
   1061 
   1062 int
   1063 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval)
   1064 {
   1065 	/* {
   1066 		syscallarg(const char *) path;
   1067 		syscallarg(char *) list;
   1068 		syscallarg(size_t) size;
   1069 	} */
   1070 	struct vnode *vp;
   1071 	char *list;
   1072 	size_t size;
   1073 	register_t listsize_usr, listsize_sys;
   1074 	int error;
   1075 
   1076 	error = namei_simple_user(SCARG(uap, path),
   1077 				NSM_NOFOLLOW_NOEMULROOT, &vp);
   1078 	if (error)
   1079 		return (error);
   1080 
   1081 	list = SCARG(uap, list);
   1082 	size = SCARG(uap, size);
   1083 
   1084 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
   1085 	    list, size, 0, l, &listsize_usr);
   1086 	if (error)
   1087 		goto out;
   1088 	if (list)
   1089 		list += listsize_usr;
   1090 	if (size)
   1091 		size -= listsize_usr;
   1092 
   1093 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
   1094 	    list, size, 0, l, &listsize_sys);
   1095 	switch (error) {
   1096 	case EPERM:
   1097 		error = 0; /* Ignore and just skip system EA */
   1098 		listsize_sys = 0;
   1099 		break;
   1100 	case 0:
   1101 		break;
   1102 	default:
   1103 		goto out;
   1104 		break;
   1105 	}
   1106 
   1107 	*retval = listsize_usr + listsize_sys;
   1108 out:
   1109 	vrele(vp);
   1110 	return (XATTR_ERRNO(error));
   1111 }
   1112 
   1113 int
   1114 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval)
   1115 {
   1116 	/* {
   1117 		syscallarg(int) fd;
   1118 		syscallarg(char *) list;
   1119 		syscallarg(size_t) size;
   1120 	} */
   1121 	struct file *fp;
   1122 	struct vnode *vp;
   1123 	char *list;
   1124 	size_t size;
   1125 	register_t listsize_usr, listsize_sys;
   1126 	int error;
   1127 
   1128 	error = fd_getvnode(SCARG(uap, fd), &fp);
   1129 	if (error)
   1130 		return (error);
   1131 	vp = fp->f_vnode;
   1132 
   1133 	list = SCARG(uap, list);
   1134 	size = SCARG(uap, size);
   1135 
   1136 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
   1137 	    list, size, 0, l, &listsize_usr);
   1138 	if (error)
   1139 		goto out;
   1140 
   1141 	if (list)
   1142 		list += listsize_usr;
   1143 	if (size)
   1144 		size -= listsize_usr;
   1145 
   1146 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
   1147 	    list, size, 0, l, &listsize_sys);
   1148 	switch (error) {
   1149 	case EPERM:
   1150 		error = 0; /* Ignore and just skip system EA */
   1151 		listsize_sys = 0;
   1152 		break;
   1153 	case 0:
   1154 		break;
   1155 	default:
   1156 		goto out;
   1157 		break;
   1158 	}
   1159 
   1160 	*retval = listsize_usr + listsize_sys;
   1161 out:
   1162 
   1163 	fd_putfile(SCARG(uap, fd));
   1164 	return (XATTR_ERRNO(error));
   1165 }
   1166 
   1167 int
   1168 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval)
   1169 {
   1170 	/* {
   1171 		syscallarg(const char *) path;
   1172 		syscallarg(const char *) name;
   1173 	} */
   1174 	struct vnode *vp;
   1175 	char attrname[XATTR_NAME_MAX];
   1176 	int attrnamespace;
   1177 	int error;
   1178 
   1179 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
   1180 	    NULL);
   1181 	if (error)
   1182 		return (error);
   1183 
   1184 	error = namei_simple_user(SCARG(uap, path),
   1185 				NSM_FOLLOW_NOEMULROOT, &vp);
   1186 	if (error)
   1187 		return (error);
   1188 
   1189 	attrnamespace = xattr_native(attrname);
   1190 
   1191 	error = extattr_delete_vp(vp, attrnamespace, attrname, l);
   1192 
   1193 	vrele(vp);
   1194 	return (XATTR_ERRNO(error));
   1195 }
   1196 
   1197 int
   1198 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval)
   1199 {
   1200 	/* {
   1201 		syscallarg(const char *) path;
   1202 		syscallarg(const char *) name;
   1203 	} */
   1204 	struct vnode *vp;
   1205 	char attrname[XATTR_NAME_MAX];
   1206 	int attrnamespace;
   1207 	int error;
   1208 
   1209 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
   1210 	    NULL);
   1211 	if (error)
   1212 		return (error);
   1213 
   1214 	error = namei_simple_user(SCARG(uap, path),
   1215 				NSM_NOFOLLOW_NOEMULROOT, &vp);
   1216 	if (error)
   1217 		return (error);
   1218 
   1219 	attrnamespace = xattr_native(attrname);
   1220 
   1221 	error = extattr_delete_vp(vp, attrnamespace, attrname, l);
   1222 
   1223 	vrele(vp);
   1224 	return (XATTR_ERRNO(error));
   1225 }
   1226 
   1227 int
   1228 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval)
   1229 {
   1230 	/* {
   1231 		syscallarg(int) fd;
   1232 		syscallarg(const char *) name;
   1233 	} */
   1234 	struct file *fp;
   1235 	struct vnode *vp;
   1236 	char attrname[XATTR_NAME_MAX];
   1237 	int attrnamespace;
   1238 	int error;
   1239 
   1240 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
   1241 	    NULL);
   1242 	if (error)
   1243 		return (error);
   1244 
   1245 	error = fd_getvnode(SCARG(uap, fd), &fp);
   1246 	if (error)
   1247 		return (error);
   1248 	vp = fp->f_vnode;
   1249 
   1250 	attrnamespace = xattr_native(attrname);
   1251 
   1252 	error = extattr_delete_vp(vp, attrnamespace, attrname, l);
   1253 
   1254 	fd_putfile(SCARG(uap, fd));
   1255 	return (XATTR_ERRNO(error));
   1256 }
   1257