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