Home | History | Annotate | Line # | Download | only in kern
vfs_xattr.c revision 1.35.6.1
      1 /*	$NetBSD: vfs_xattr.c,v 1.35.6.1 2021/08/01 22:42:39 thorpej 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.35.6.1 2021/08/01 22:42:39 thorpej 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_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_offset = 0;
    387 		if (nbytes > INT_MAX) {
    388 			error = EINVAL;
    389 			goto done;
    390 		}
    391 		auio.uio_resid = nbytes;
    392 		auio.uio_rw = UIO_READ;
    393 		KASSERT(l == curlwp);
    394 		auio.uio_vmspace = l->l_proc->p_vmspace;
    395 		auiop = &auio;
    396 		cnt = nbytes;
    397 	} else
    398 		sizep = &size;
    399 
    400 	error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
    401 				flag, l->l_cred);
    402 
    403 	if (auiop != NULL) {
    404 		cnt -= auio.uio_resid;
    405 		retval[0] = cnt;
    406 
    407 		ktruser("xattr-list", data, cnt, 0);
    408 	} else
    409 		retval[0] = size;
    410 
    411  done:
    412 	VOP_UNLOCK(vp);
    413 	return (error);
    414 }
    415 
    416 /*****************************************************************************
    417  * BSD <sys/extattr.h> API for file system extended attributes
    418  *****************************************************************************/
    419 
    420 int
    421 sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, register_t *retval)
    422 {
    423 	/* {
    424 		syscallarg(int) fd;
    425 		syscallarg(int) attrnamespace;
    426 		syscallarg(const char *) attrname;
    427 		syscallarg(const void *) data;
    428 		syscallarg(size_t) nbytes;
    429 	} */
    430 	struct file *fp;
    431 	struct vnode *vp;
    432 	char attrname[EXTATTR_MAXNAMELEN];
    433 	int error;
    434 
    435 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    436 	    NULL);
    437 	if (error)
    438 		return (error);
    439 
    440 	error = fd_getvnode(SCARG(uap, fd), &fp);
    441 	if (error)
    442 		return (error);
    443 	vp = fp->f_vnode;
    444 
    445 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
    446 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
    447 
    448 	fd_putfile(SCARG(uap, fd));
    449 	return (error);
    450 }
    451 
    452 int
    453 sys_extattr_set_file(struct lwp *l, const struct sys_extattr_set_file_args *uap, register_t *retval)
    454 {
    455 	/* {
    456 		syscallarg(const char *) path;
    457 		syscallarg(int) attrnamespace;
    458 		syscallarg(const char *) attrname;
    459 		syscallarg(const void *) data;
    460 		syscallarg(size_t) nbytes;
    461 	} */
    462 	struct vnode *vp;
    463 	char attrname[EXTATTR_MAXNAMELEN];
    464 	int error;
    465 
    466 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    467 	    NULL);
    468 	if (error)
    469 		return (error);
    470 
    471 	error = namei_simple_user(SCARG(uap, path),
    472 				NSM_FOLLOW_NOEMULROOT, &vp);
    473 	if (error)
    474 		return (error);
    475 
    476 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
    477 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
    478 
    479 	vrele(vp);
    480 	return (error);
    481 }
    482 
    483 int
    484 sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval)
    485 {
    486 	/* {
    487 		syscallarg(const char *) path;
    488 		syscallarg(int) attrnamespace;
    489 		syscallarg(const char *) attrname;
    490 		syscallarg(const void *) data;
    491 		syscallarg(size_t) nbytes;
    492 	} */
    493 	struct vnode *vp;
    494 	char attrname[EXTATTR_MAXNAMELEN];
    495 	int error;
    496 
    497 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    498 	    NULL);
    499 	if (error)
    500 		return (error);
    501 
    502 	error = namei_simple_user(SCARG(uap, path),
    503 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    504 	if (error)
    505 		return (error);
    506 
    507 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
    508 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
    509 
    510 	vrele(vp);
    511 	return (error);
    512 }
    513 
    514 int
    515 sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval)
    516 {
    517 	/* {
    518 		syscallarg(int) fd;
    519 		syscallarg(int) attrnamespace;
    520 		syscallarg(const char *) attrname;
    521 		syscallarg(void *) data;
    522 		syscallarg(size_t) nbytes;
    523 	} */
    524 	struct file *fp;
    525 	struct vnode *vp;
    526 	char attrname[EXTATTR_MAXNAMELEN];
    527 	int error;
    528 
    529 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    530 	    NULL);
    531 	if (error)
    532 		return (error);
    533 
    534 	error = fd_getvnode(SCARG(uap, fd), &fp);
    535 	if (error)
    536 		return (error);
    537 	vp = fp->f_vnode;
    538 
    539 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    540 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    541 
    542 	fd_putfile(SCARG(uap, fd));
    543 	return (error);
    544 }
    545 
    546 int
    547 sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval)
    548 {
    549 	/* {
    550 		syscallarg(const char *) path;
    551 		syscallarg(int) attrnamespace;
    552 		syscallarg(const char *) attrname;
    553 		syscallarg(void *) data;
    554 		syscallarg(size_t) nbytes;
    555 	} */
    556 	struct vnode *vp;
    557 	char attrname[EXTATTR_MAXNAMELEN];
    558 	int error;
    559 
    560 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    561 	    NULL);
    562 	if (error)
    563 		return (error);
    564 
    565 	error = namei_simple_user(SCARG(uap, path),
    566 				NSM_FOLLOW_NOEMULROOT, &vp);
    567 	if (error)
    568 		return (error);
    569 
    570 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    571 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    572 
    573 	vrele(vp);
    574 	return (error);
    575 }
    576 
    577 int
    578 sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval)
    579 {
    580 	/* {
    581 		syscallarg(const char *) path;
    582 		syscallarg(int) attrnamespace;
    583 		syscallarg(const char *) attrname;
    584 		syscallarg(void *) data;
    585 		syscallarg(size_t) nbytes;
    586 	} */
    587 	struct vnode *vp;
    588 	char attrname[EXTATTR_MAXNAMELEN];
    589 	int error;
    590 
    591 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    592 	    NULL);
    593 	if (error)
    594 		return (error);
    595 
    596 	error = namei_simple_user(SCARG(uap, path),
    597 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    598 	if (error)
    599 		return (error);
    600 
    601 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    602 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    603 
    604 	vrele(vp);
    605 	return (error);
    606 }
    607 
    608 int
    609 sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval)
    610 {
    611 	/* {
    612 		syscallarg(int) fd;
    613 		syscallarg(int) attrnamespace;
    614 		syscallarg(const char *) attrname;
    615 	} */
    616 	struct file *fp;
    617 	struct vnode *vp;
    618 	char attrname[EXTATTR_MAXNAMELEN];
    619 	int error;
    620 
    621 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    622 	    NULL);
    623 	if (error)
    624 		return (error);
    625 
    626 	error = fd_getvnode(SCARG(uap, fd), &fp);
    627 	if (error)
    628 		return (error);
    629 	vp = fp->f_vnode;
    630 
    631 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    632 
    633 	fd_putfile(SCARG(uap, fd));
    634 	return (error);
    635 }
    636 
    637 int
    638 sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval)
    639 {
    640 	/* {
    641 		syscallarg(const char *) path;
    642 		syscallarg(int) attrnamespace;
    643 		syscallarg(const char *) attrname;
    644 	} */
    645 	struct vnode *vp;
    646 	char attrname[EXTATTR_MAXNAMELEN];
    647 	int error;
    648 
    649 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    650 	    NULL);
    651 	if (error)
    652 		return (error);
    653 
    654 	error = namei_simple_user(SCARG(uap, path),
    655 				NSM_FOLLOW_NOEMULROOT, &vp);
    656 	if (error)
    657 		return (error);
    658 
    659 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    660 
    661 	vrele(vp);
    662 	return (error);
    663 }
    664 
    665 int
    666 sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval)
    667 {
    668 	/* {
    669 		syscallarg(const char *) path;
    670 		syscallarg(int) attrnamespace;
    671 		syscallarg(const char *) attrname;
    672 	} */
    673 	struct vnode *vp;
    674 	char attrname[EXTATTR_MAXNAMELEN];
    675 	int error;
    676 
    677 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    678 	    NULL);
    679 	if (error)
    680 		return (error);
    681 
    682 	error = namei_simple_user(SCARG(uap, path),
    683 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    684 	if (error)
    685 		return (error);
    686 
    687 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    688 
    689 	vrele(vp);
    690 	return (error);
    691 }
    692 
    693 int
    694 sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval)
    695 {
    696 	/* {
    697 		syscallarg(int) fd;
    698 		syscallarg(int) attrnamespace;
    699 		syscallarg(void *) data;
    700 		syscallarg(size_t) nbytes;
    701 	} */
    702 	struct file *fp;
    703 	struct vnode *vp;
    704 	int error;
    705 
    706 	error = fd_getvnode(SCARG(uap, fd), &fp);
    707 	if (error)
    708 		return (error);
    709 	vp = fp->f_vnode;
    710 
    711 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    712 	    SCARG(uap, data), SCARG(uap, nbytes),
    713 	    EXTATTR_LIST_LENPREFIX, l, retval);
    714 
    715 	fd_putfile(SCARG(uap, fd));
    716 	return (error);
    717 }
    718 
    719 int
    720 sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval)
    721 {
    722 	/* {
    723 		syscallarg(const char *) path;
    724 		syscallarg(int) attrnamespace;
    725 		syscallarg(void *) data;
    726 		syscallarg(size_t) nbytes;
    727 	} */
    728 	struct vnode *vp;
    729 	int error;
    730 
    731 	error = namei_simple_user(SCARG(uap, path),
    732 				NSM_FOLLOW_NOEMULROOT, &vp);
    733 	if (error)
    734 		return (error);
    735 
    736 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    737 	    SCARG(uap, data), SCARG(uap, nbytes),
    738 	    EXTATTR_LIST_LENPREFIX, l, retval);
    739 
    740 	vrele(vp);
    741 	return (error);
    742 }
    743 
    744 int
    745 sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval)
    746 {
    747 	/* {
    748 		syscallarg(const char *) path;
    749 		syscallarg(int) attrnamespace;
    750 		syscallarg(void *) data;
    751 		syscallarg(size_t) nbytes;
    752 	} */
    753 	struct vnode *vp;
    754 	int error;
    755 
    756 	error = namei_simple_user(SCARG(uap, path),
    757 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    758 	if (error)
    759 		return (error);
    760 
    761 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    762 	    SCARG(uap, data), SCARG(uap, nbytes),
    763 	    EXTATTR_LIST_LENPREFIX, l, retval);
    764 
    765 	vrele(vp);
    766 	return (error);
    767 }
    768 
    769 /*****************************************************************************
    770  * Linux-compatible <sys/xattr.h> API for file system extended attributes
    771  *****************************************************************************/
    772 
    773 #define MATCH_NS(ns, key) (strncmp(ns, key, sizeof(ns) - 1) == 0)
    774 static int
    775 xattr_native(const char *key) {
    776 	if (MATCH_NS("system.", key))
    777 		return EXTATTR_NAMESPACE_SYSTEM;
    778 	else if (MATCH_NS("user.", key))
    779 		return EXTATTR_NAMESPACE_USER;
    780 	else if (MATCH_NS("security.", key))
    781 		return EXTATTR_NAMESPACE_SYSTEM;
    782 	else if (MATCH_NS("trusted.", key))
    783 		return EXTATTR_NAMESPACE_SYSTEM;
    784 	else
    785 		return EXTATTR_NAMESPACE_USER;
    786 
    787 }
    788 #undef MATCH_NS
    789 
    790 #define XATTR_ERRNO(e) ((e) == EOPNOTSUPP ? ENOTSUP : (e))
    791 
    792 int
    793 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval)
    794 {
    795 	/* {
    796 		syscallarg(const char *) path;
    797 		syscallarg(const char *) name;
    798 		syscallarg(void *) value;
    799 		syscallarg(size_t) size;
    800 		syscallarg(int) flags;
    801 	} */
    802 	struct vnode *vp;
    803 	char attrname[XATTR_NAME_MAX];
    804 	int attrnamespace;
    805 	register_t attrlen;
    806 	int error;
    807 
    808 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    809 	    NULL);
    810 	if (error)
    811 		goto out;
    812 
    813 	error = namei_simple_user(SCARG(uap, path),
    814 				NSM_FOLLOW_NOEMULROOT, &vp);
    815 	if (error)
    816 		goto out;
    817 
    818 	attrnamespace = xattr_native(attrname);
    819 
    820 	error = extattr_set_vp(vp, attrnamespace,
    821 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
    822 	    &attrlen, SCARG(uap, flags));
    823 
    824 	vrele(vp);
    825 out:
    826 	*retval = (error == 0) ? 0 : -1;
    827 	return (XATTR_ERRNO(error));
    828 }
    829 
    830 int
    831 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval)
    832 {
    833 	/* {
    834 		syscallarg(const char *) path;
    835 		syscallarg(const char *) name;
    836 		syscallarg(void *) value;
    837 		syscallarg(size_t) size;
    838 		syscallarg(int) flags;
    839 	} */
    840 	struct vnode *vp;
    841 	char attrname[XATTR_NAME_MAX];
    842 	int attrnamespace;
    843 	register_t attrlen;
    844 	int error;
    845 
    846 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    847 	    NULL);
    848 	if (error)
    849 		goto out;
    850 
    851 	error = namei_simple_user(SCARG(uap, path),
    852 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    853 	if (error)
    854 		goto out;
    855 
    856 	attrnamespace = xattr_native(attrname);
    857 
    858 	error = extattr_set_vp(vp, attrnamespace,
    859 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
    860 	    &attrlen, SCARG(uap, flags));
    861 
    862 	vrele(vp);
    863 out:
    864 	*retval = (error == 0) ? 0 : -1;
    865 	return (XATTR_ERRNO(error));
    866 }
    867 
    868 int
    869 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval)
    870 {
    871 	/* {
    872 		syscallarg(int) fd;
    873 		syscallarg(const char *) name;
    874 		syscallarg(void *) value;
    875 		syscallarg(size_t) size;
    876 		syscallarg(int) flags;
    877 	} */
    878 	struct file *fp;
    879 	struct vnode *vp;
    880 	char attrname[XATTR_NAME_MAX];
    881 	int attrnamespace;
    882 	register_t attrlen;
    883 	int error;
    884 
    885 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    886 	    NULL);
    887 	if (error)
    888 		goto out;
    889 
    890 	error = fd_getvnode(SCARG(uap, fd), &fp);
    891 	if (error)
    892 		goto out;
    893 	vp = fp->f_vnode;
    894 
    895 	attrnamespace = xattr_native(attrname);
    896 
    897 	error = extattr_set_vp(vp, attrnamespace,
    898 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
    899 	    &attrlen, SCARG(uap, flags));
    900 
    901 	fd_putfile(SCARG(uap, fd));
    902 out:
    903 	*retval = (error == 0) ? 0 : -1;
    904 	return (XATTR_ERRNO(error));
    905 }
    906 
    907 int
    908 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval)
    909 {
    910 	/* {
    911 		syscallarg(const char *) path;
    912 		syscallarg(const char *) name;
    913 		syscallarg(void *) value;
    914 		syscallarg(size_t) size;
    915 	} */
    916 	struct vnode *vp;
    917 	char attrname[XATTR_NAME_MAX];
    918 	int attrnamespace;
    919 	int error;
    920 
    921 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    922 	    NULL);
    923 	if (error)
    924 		return (error);
    925 
    926 	error = namei_simple_user(SCARG(uap, path),
    927 				NSM_FOLLOW_NOEMULROOT, &vp);
    928 	if (error)
    929 		return (error);
    930 
    931 	attrnamespace = xattr_native(attrname);
    932 
    933 	error = extattr_get_vp(vp, attrnamespace,
    934 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    935 
    936 	vrele(vp);
    937 	return (XATTR_ERRNO(error));
    938 }
    939 
    940 int
    941 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, 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),
    960 				NSM_NOFOLLOW_NOEMULROOT, &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_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval)
    975 {
    976 	/* {
    977 		syscallarg(int) fd;
    978 		syscallarg(const char *) name;
    979 		syscallarg(void *) value;
    980 		syscallarg(size_t) size;
    981 	} */
    982 	struct file *fp;
    983 	struct vnode *vp;
    984 	char attrname[XATTR_NAME_MAX];
    985 	int attrnamespace;
    986 	int error;
    987 
    988 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    989 	    NULL);
    990 	if (error)
    991 		return (error);
    992 
    993 	error = fd_getvnode(SCARG(uap, fd), &fp);
    994 	if (error)
    995 		return (error);
    996 	vp = fp->f_vnode;
    997 
    998 	attrnamespace = xattr_native(attrname);
    999 
   1000 	error = extattr_get_vp(vp, attrnamespace,
   1001 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
   1002 
   1003 	fd_putfile(SCARG(uap, fd));
   1004 	return (XATTR_ERRNO(error));
   1005 }
   1006 
   1007 int
   1008 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval)
   1009 {
   1010 	/* {
   1011 		syscallarg(const char *) path;
   1012 		syscallarg(char *) list;
   1013 		syscallarg(size_t) size;
   1014 	} */
   1015 	struct vnode *vp;
   1016 	char *list;
   1017 	size_t size;
   1018 	register_t listsize_usr, listsize_sys;
   1019 	int error;
   1020 
   1021 	error = namei_simple_user(SCARG(uap, path),
   1022 				NSM_FOLLOW_NOEMULROOT, &vp);
   1023 	if (error)
   1024 		return (error);
   1025 
   1026 	list = SCARG(uap, list);
   1027 	size = SCARG(uap, size);
   1028 
   1029 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
   1030 	    list, size, 0, l, &listsize_usr);
   1031 	if (error)
   1032 		goto out;
   1033 
   1034 	if (list)
   1035 		list += listsize_usr;
   1036 	if (size)
   1037 		size -= listsize_usr;
   1038 
   1039 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
   1040 	    list, size, 0, l, &listsize_sys);
   1041 	switch (error) {
   1042 	case EPERM:
   1043 		error = 0; /* Ignore and just skip system EA */
   1044 		listsize_sys = 0;
   1045 		break;
   1046 	case 0:
   1047 		break;
   1048 	default:
   1049 		goto out;
   1050 		break;
   1051 	}
   1052 
   1053 	*retval = listsize_usr + listsize_sys;
   1054 
   1055 out:
   1056 	vrele(vp);
   1057 	return (XATTR_ERRNO(error));
   1058 }
   1059 
   1060 int
   1061 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval)
   1062 {
   1063 	/* {
   1064 		syscallarg(const char *) path;
   1065 		syscallarg(char *) list;
   1066 		syscallarg(size_t) size;
   1067 	} */
   1068 	struct vnode *vp;
   1069 	char *list;
   1070 	size_t size;
   1071 	register_t listsize_usr, listsize_sys;
   1072 	int error;
   1073 
   1074 	error = namei_simple_user(SCARG(uap, path),
   1075 				NSM_NOFOLLOW_NOEMULROOT, &vp);
   1076 	if (error)
   1077 		return (error);
   1078 
   1079 	list = SCARG(uap, list);
   1080 	size = SCARG(uap, size);
   1081 
   1082 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
   1083 	    list, size, 0, l, &listsize_usr);
   1084 	if (error)
   1085 		goto out;
   1086 	if (list)
   1087 		list += listsize_usr;
   1088 	if (size)
   1089 		size -= listsize_usr;
   1090 
   1091 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
   1092 	    list, size, 0, l, &listsize_sys);
   1093 	switch (error) {
   1094 	case EPERM:
   1095 		error = 0; /* Ignore and just skip system EA */
   1096 		listsize_sys = 0;
   1097 		break;
   1098 	case 0:
   1099 		break;
   1100 	default:
   1101 		goto out;
   1102 		break;
   1103 	}
   1104 
   1105 	*retval = listsize_usr + listsize_sys;
   1106 out:
   1107 	vrele(vp);
   1108 	return (XATTR_ERRNO(error));
   1109 }
   1110 
   1111 int
   1112 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval)
   1113 {
   1114 	/* {
   1115 		syscallarg(int) fd;
   1116 		syscallarg(char *) list;
   1117 		syscallarg(size_t) size;
   1118 	} */
   1119 	struct file *fp;
   1120 	struct vnode *vp;
   1121 	char *list;
   1122 	size_t size;
   1123 	register_t listsize_usr, listsize_sys;
   1124 	int error;
   1125 
   1126 	error = fd_getvnode(SCARG(uap, fd), &fp);
   1127 	if (error)
   1128 		return (error);
   1129 	vp = fp->f_vnode;
   1130 
   1131 	list = SCARG(uap, list);
   1132 	size = SCARG(uap, size);
   1133 
   1134 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
   1135 	    list, size, 0, l, &listsize_usr);
   1136 	if (error)
   1137 		goto out;
   1138 
   1139 	if (list)
   1140 		list += listsize_usr;
   1141 	if (size)
   1142 		size -= listsize_usr;
   1143 
   1144 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
   1145 	    list, size, 0, l, &listsize_sys);
   1146 	switch (error) {
   1147 	case EPERM:
   1148 		error = 0; /* Ignore and just skip system EA */
   1149 		listsize_sys = 0;
   1150 		break;
   1151 	case 0:
   1152 		break;
   1153 	default:
   1154 		goto out;
   1155 		break;
   1156 	}
   1157 
   1158 	*retval = listsize_usr + listsize_sys;
   1159 out:
   1160 
   1161 	fd_putfile(SCARG(uap, fd));
   1162 	return (XATTR_ERRNO(error));
   1163 }
   1164 
   1165 int
   1166 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval)
   1167 {
   1168 	/* {
   1169 		syscallarg(const char *) path;
   1170 		syscallarg(const char *) name;
   1171 	} */
   1172 	struct vnode *vp;
   1173 	char attrname[XATTR_NAME_MAX];
   1174 	int attrnamespace;
   1175 	int error;
   1176 
   1177 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
   1178 	    NULL);
   1179 	if (error)
   1180 		return (error);
   1181 
   1182 	error = namei_simple_user(SCARG(uap, path),
   1183 				NSM_FOLLOW_NOEMULROOT, &vp);
   1184 	if (error)
   1185 		return (error);
   1186 
   1187 	attrnamespace = xattr_native(attrname);
   1188 
   1189 	error = extattr_delete_vp(vp, attrnamespace, attrname, l);
   1190 
   1191 	vrele(vp);
   1192 	return (XATTR_ERRNO(error));
   1193 }
   1194 
   1195 int
   1196 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval)
   1197 {
   1198 	/* {
   1199 		syscallarg(const char *) path;
   1200 		syscallarg(const char *) name;
   1201 	} */
   1202 	struct vnode *vp;
   1203 	char attrname[XATTR_NAME_MAX];
   1204 	int attrnamespace;
   1205 	int error;
   1206 
   1207 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
   1208 	    NULL);
   1209 	if (error)
   1210 		return (error);
   1211 
   1212 	error = namei_simple_user(SCARG(uap, path),
   1213 				NSM_NOFOLLOW_NOEMULROOT, &vp);
   1214 	if (error)
   1215 		return (error);
   1216 
   1217 	attrnamespace = xattr_native(attrname);
   1218 
   1219 	error = extattr_delete_vp(vp, attrnamespace, attrname, l);
   1220 
   1221 	vrele(vp);
   1222 	return (XATTR_ERRNO(error));
   1223 }
   1224 
   1225 int
   1226 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval)
   1227 {
   1228 	/* {
   1229 		syscallarg(int) fd;
   1230 		syscallarg(const char *) name;
   1231 	} */
   1232 	struct file *fp;
   1233 	struct vnode *vp;
   1234 	char attrname[XATTR_NAME_MAX];
   1235 	int attrnamespace;
   1236 	int error;
   1237 
   1238 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
   1239 	    NULL);
   1240 	if (error)
   1241 		return (error);
   1242 
   1243 	error = fd_getvnode(SCARG(uap, fd), &fp);
   1244 	if (error)
   1245 		return (error);
   1246 	vp = fp->f_vnode;
   1247 
   1248 	attrnamespace = xattr_native(attrname);
   1249 
   1250 	error = extattr_delete_vp(vp, attrnamespace, attrname, l);
   1251 
   1252 	fd_putfile(SCARG(uap, fd));
   1253 	return (XATTR_ERRNO(error));
   1254 }
   1255