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