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
ktr_xattr_name(const char * str)96 ktr_xattr_name(const char *str)
97 {
98           ktrkuser("xattr-name", (void *)__UNCONST(str), strlen(str));
99 }
100 
101 static void
ktr_xattr_val(const void * data,size_t cnt)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
extattr_check_cred(struct vnode * vp,int attrspace,kauth_cred_t cred,int access)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
vfs_stdextattrctl(struct mount * mp,int cmt,struct vnode * vp,int attrnamespace,const char * attrname)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
sys_extattrctl(struct lwp * l,const struct sys_extattrctl_args * uap,register_t * retval)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
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)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
extattr_get_vp(struct vnode * vp,int attrnamespace,const char * attrname,void * data,size_t nbytes,struct lwp * l,register_t * retval)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
extattr_delete_vp(struct vnode * vp,int attrnamespace,const char * attrname,struct lwp * l)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
extattr_list_vp(struct vnode * vp,int attrnamespace,void * data,size_t nbytes,int flag,struct lwp * l,register_t * retval)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
sys_extattr_set_fd(struct lwp * l,const struct sys_extattr_set_fd_args * uap,register_t * retval)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
sys_extattr_set_file(struct lwp * l,const struct sys_extattr_set_file_args * uap,register_t * retval)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
sys_extattr_set_link(struct lwp * l,const struct sys_extattr_set_link_args * uap,register_t * retval)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
sys_extattr_get_fd(struct lwp * l,const struct sys_extattr_get_fd_args * uap,register_t * retval)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
sys_extattr_get_file(struct lwp * l,const struct sys_extattr_get_file_args * uap,register_t * retval)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
sys_extattr_get_link(struct lwp * l,const struct sys_extattr_get_link_args * uap,register_t * retval)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
sys_extattr_delete_fd(struct lwp * l,const struct sys_extattr_delete_fd_args * uap,register_t * retval)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
sys_extattr_delete_file(struct lwp * l,const struct sys_extattr_delete_file_args * uap,register_t * retval)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
sys_extattr_delete_link(struct lwp * l,const struct sys_extattr_delete_link_args * uap,register_t * retval)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
sys_extattr_list_fd(struct lwp * l,const struct sys_extattr_list_fd_args * uap,register_t * retval)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
sys_extattr_list_file(struct lwp * l,const struct sys_extattr_list_file_args * uap,register_t * retval)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
sys_extattr_list_link(struct lwp * l,const struct sys_extattr_list_link_args * uap,register_t * retval)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
xattr_native(const char * key)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
sys_setxattr(struct lwp * l,const struct sys_setxattr_args * uap,register_t * retval)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
sys_lsetxattr(struct lwp * l,const struct sys_lsetxattr_args * uap,register_t * retval)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
sys_fsetxattr(struct lwp * l,const struct sys_fsetxattr_args * uap,register_t * retval)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
sys_getxattr(struct lwp * l,const struct sys_getxattr_args * uap,register_t * retval)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
sys_lgetxattr(struct lwp * l,const struct sys_lgetxattr_args * uap,register_t * retval)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
sys_fgetxattr(struct lwp * l,const struct sys_fgetxattr_args * uap,register_t * retval)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
sys_listxattr(struct lwp * l,const struct sys_listxattr_args * uap,register_t * retval)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
sys_llistxattr(struct lwp * l,const struct sys_llistxattr_args * uap,register_t * retval)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
sys_flistxattr(struct lwp * l,const struct sys_flistxattr_args * uap,register_t * retval)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
sys_removexattr(struct lwp * l,const struct sys_removexattr_args * uap,register_t * retval)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
sys_lremovexattr(struct lwp * l,const struct sys_lremovexattr_args * uap,register_t * retval)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
sys_fremovexattr(struct lwp * l,const struct sys_fremovexattr_args * uap,register_t * retval)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