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 */
98int
99extattr_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*/
115int
116vfs_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 */
132int
133sys_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 */
203static int
204extattr_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 */
270static int
271extattr_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 */
331static int
332extattr_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 */
355static int
356extattr_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
408int
409sys_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
440int
441sys_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
471int
472sys_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
502int
503sys_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
534int
535sys_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
565int
566sys_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
596int
597sys_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
625int
626sys_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
653int
654sys_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
681int
682sys_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
707int
708sys_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
732int
733sys_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)
762static int
763xattr_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
780int
781sys_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);
813out:
814 *retval = (error == 0) ? 0 : -1;
815 return (XATTR_ERRNO(error));
816}
817
818int
819sys_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);
851out:
852 *retval = (error == 0) ? 0 : -1;
853 return (XATTR_ERRNO(error));
854}
855
856int
857sys_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));
890out:
891 *retval = (error == 0) ? 0 : -1;
892 return (XATTR_ERRNO(error));
893}
894
895int
896sys_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
928int
929sys_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
961int
962sys_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
995int
996sys_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
1043out:
1044 vrele(vp);
1045 return (XATTR_ERRNO(error));
1046}
1047
1048int
1049sys_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;
1094out:
1095 vrele(vp);
1096 return (XATTR_ERRNO(error));
1097}
1098
1099int
1100sys_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;
1147out:
1148
1149 fd_putfile(SCARG(uap, fd));
1150 return (XATTR_ERRNO(error));
1151}
1152
1153int
1154sys_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
1183int
1184sys_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
1213int
1214sys_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