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