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