1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1999-2001 Robert N. M. Watson
5 * All rights reserved.
6 *
7 * This software was developed by Robert Watson for the TrustedBSD Project.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/capsicum.h>
34 #include <sys/lock.h>
35 #include <sys/mount.h>
36 #include <sys/mutex.h>
37 #include <sys/sysproto.h>
38 #include <sys/fcntl.h>
39 #include <sys/namei.h>
40 #include <sys/filedesc.h>
41 #include <sys/limits.h>
42 #include <sys/vnode.h>
43 #include <sys/proc.h>
44 #include <sys/extattr.h>
45 #include <sys/syscallsubr.h>
46
47 #include <security/audit/audit.h>
48 #include <security/mac/mac_framework.h>
49
50 static int user_extattr_set_path(struct thread *td, const char *path,
51 int attrnamespace, const char *attrname, void *data,
52 size_t nbytes, int follow);
53 static int user_extattr_get_path(struct thread *td, const char *path,
54 int attrnamespace, const char *attrname, void *data,
55 size_t nbytes, int follow);
56 static int user_extattr_delete_path(struct thread *td, const char *path,
57 int attrnamespace, const char *attrname, int follow);
58 static int user_extattr_list_path(struct thread *td, const char *path,
59 int attrnamespace, void *data, size_t nbytes, int follow);
60
61 /*
62 * Syscall to push extended attribute configuration information into the VFS.
63 * Accepts a path, which it converts to a mountpoint, as well as a command
64 * (int cmd), and attribute name and misc data.
65 *
66 * Currently this is used only by UFS1 extended attributes.
67 */
68 #ifndef _SYS_SYSPROTO_H_
69 struct extattrctl_args {
70 const char *path;
71 int cmd;
72 const char *filename;
73 int attrnamespace;
74 const char *attrname;
75 };
76 #endif
77 int
sys_extattrctl(struct thread * td,struct extattrctl_args * uap)78 sys_extattrctl(struct thread *td, struct extattrctl_args *uap)
79 {
80 struct vnode *filename_vp;
81 struct nameidata nd;
82 struct mount *mp, *mp_writable;
83 char attrname[EXTATTR_MAXNAMELEN + 1];
84 int error;
85
86 AUDIT_ARG_CMD(uap->cmd);
87 AUDIT_ARG_VALUE(uap->attrnamespace);
88 /*
89 * uap->attrname is not always defined. We check again later when we
90 * invoke the VFS call so as to pass in NULL there if needed.
91 */
92 if (uap->attrname != NULL) {
93 error = copyinstr(uap->attrname, attrname, sizeof(attrname),
94 NULL);
95 if (error)
96 return (error);
97 }
98 AUDIT_ARG_TEXT(attrname);
99
100 mp = NULL;
101 filename_vp = NULL;
102 if (uap->filename != NULL) {
103 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE2, UIO_USERSPACE,
104 uap->filename);
105 error = namei(&nd);
106 if (error)
107 return (error);
108 filename_vp = nd.ni_vp;
109 NDFREE_PNBUF(&nd);
110 }
111
112 /* uap->path is always defined. */
113 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
114 uap->path);
115 error = namei(&nd);
116 if (error)
117 goto out;
118 mp = nd.ni_vp->v_mount;
119 error = vfs_busy(mp, 0);
120 if (error) {
121 vput(nd.ni_vp);
122 NDFREE_PNBUF(&nd);
123 mp = NULL;
124 goto out;
125 }
126 VOP_UNLOCK(nd.ni_vp);
127 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | V_PCATCH);
128 vrele(nd.ni_vp);
129 NDFREE_PNBUF(&nd);
130 if (error)
131 goto out;
132 if (filename_vp != NULL) {
133 /*
134 * uap->filename is not always defined. If it is,
135 * grab a vnode lock, which VFS_EXTATTRCTL() will
136 * later release.
137 */
138 error = vn_lock(filename_vp, LK_EXCLUSIVE);
139 if (error) {
140 vn_finished_write(mp_writable);
141 goto out;
142 }
143 }
144
145 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
146 uap->attrname != NULL ? attrname : NULL);
147
148 vn_finished_write(mp_writable);
149 out:
150 if (mp != NULL)
151 vfs_unbusy(mp);
152
153 /*
154 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
155 * so vrele it if it is defined.
156 */
157 if (filename_vp != NULL)
158 vrele(filename_vp);
159 return (error);
160 }
161
162 /*-
163 * Set a named extended attribute on a file or directory
164 *
165 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
166 * kernelspace string pointer "attrname", userspace buffer
167 * pointer "data", buffer length "nbytes", thread "td".
168 * Returns: 0 on success, an error number otherwise
169 * Locks: none
170 * References: vp must be a valid reference for the duration of the call
171 */
172 static int
extattr_set_vp(struct vnode * vp,int attrnamespace,const char * attrname,void * data,size_t nbytes,struct thread * td)173 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
174 void *data, size_t nbytes, struct thread *td)
175 {
176 struct mount *mp;
177 struct uio auio;
178 struct iovec aiov;
179 ssize_t cnt;
180 int error;
181
182 if (nbytes > IOSIZE_MAX)
183 return (EINVAL);
184
185 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
186 if (error)
187 return (error);
188 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
189
190 aiov.iov_base = data;
191 aiov.iov_len = nbytes;
192 auio.uio_iov = &aiov;
193 auio.uio_iovcnt = 1;
194 auio.uio_offset = 0;
195 auio.uio_resid = nbytes;
196 auio.uio_rw = UIO_WRITE;
197 auio.uio_segflg = UIO_USERSPACE;
198 auio.uio_td = td;
199 cnt = nbytes;
200
201 #ifdef MAC
202 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
203 attrname);
204 if (error)
205 goto done;
206 #endif
207
208 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
209 td->td_ucred, td);
210 cnt -= auio.uio_resid;
211 td->td_retval[0] = cnt;
212
213 #ifdef MAC
214 done:
215 #endif
216 VOP_UNLOCK(vp);
217 vn_finished_write(mp);
218 return (error);
219 }
220
221 #ifndef _SYS_SYSPROTO_H_
222 struct extattr_set_fd_args {
223 int fd;
224 int attrnamespace;
225 const char *attrname;
226 void *data;
227 size_t nbytes;
228 };
229 #endif
230 int
sys_extattr_set_fd(struct thread * td,struct extattr_set_fd_args * uap)231 sys_extattr_set_fd(struct thread *td, struct extattr_set_fd_args *uap)
232 {
233 char attrname[EXTATTR_MAXNAMELEN + 1];
234 int error;
235
236 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
237 if (error)
238 return (error);
239 return (kern_extattr_set_fd(td, uap->fd, uap->attrnamespace,
240 attrname, uap->data, uap->nbytes));
241 }
242
243 int
kern_extattr_set_fp(struct thread * td,struct file * fp,int attrnamespace,const char * attrname,void * data,size_t nbytes)244 kern_extattr_set_fp(struct thread *td, struct file *fp, int attrnamespace,
245 const char *attrname, void *data, size_t nbytes)
246 {
247
248 return (extattr_set_vp(fp->f_vnode, attrnamespace, attrname, data,
249 nbytes, td));
250 }
251
252 int
kern_extattr_set_fd(struct thread * td,int fd,int attrnamespace,const char * attrname,void * data,size_t nbytes)253 kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace,
254 const char *attrname, void *data, size_t nbytes)
255 {
256 struct file *fp;
257 cap_rights_t rights;
258 int error;
259
260 AUDIT_ARG_FD(fd);
261 AUDIT_ARG_VALUE(attrnamespace);
262 AUDIT_ARG_TEXT(attrname);
263
264 error = getvnode_path(td, fd,
265 cap_rights_init_one(&rights, CAP_EXTATTR_SET), NULL, &fp);
266 if (error)
267 return (error);
268
269 error = kern_extattr_set_fp(td, fp, attrnamespace, attrname, data,
270 nbytes);
271 fdrop(fp, td);
272
273 return (error);
274 }
275
276 #ifndef _SYS_SYSPROTO_H_
277 struct extattr_set_file_args {
278 const char *path;
279 int attrnamespace;
280 const char *attrname;
281 void *data;
282 size_t nbytes;
283 };
284 #endif
285 int
sys_extattr_set_file(struct thread * td,struct extattr_set_file_args * uap)286 sys_extattr_set_file(struct thread *td, struct extattr_set_file_args *uap)
287 {
288
289 return (user_extattr_set_path(td, uap->path, uap->attrnamespace,
290 uap->attrname, uap->data, uap->nbytes, FOLLOW));
291 }
292
293 #ifndef _SYS_SYSPROTO_H_
294 struct extattr_set_link_args {
295 const char *path;
296 int attrnamespace;
297 const char *attrname;
298 void *data;
299 size_t nbytes;
300 };
301 #endif
302 int
sys_extattr_set_link(struct thread * td,struct extattr_set_link_args * uap)303 sys_extattr_set_link(struct thread *td, struct extattr_set_link_args *uap)
304 {
305
306 return (user_extattr_set_path(td, uap->path, uap->attrnamespace,
307 uap->attrname, uap->data, uap->nbytes, NOFOLLOW));
308 }
309
310 static int
user_extattr_set_path(struct thread * td,const char * path,int attrnamespace,const char * uattrname,void * data,size_t nbytes,int follow)311 user_extattr_set_path(struct thread *td, const char *path, int attrnamespace,
312 const char *uattrname, void *data, size_t nbytes, int follow)
313 {
314 char attrname[EXTATTR_MAXNAMELEN + 1];
315 int error;
316
317 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
318 if (error)
319 return (error);
320 return (kern_extattr_set_path(td, path, attrnamespace,
321 attrname, data, nbytes, follow, UIO_USERSPACE));
322 }
323
324 int
kern_extattr_set_path(struct thread * td,const char * path,int attrnamespace,const char * attrname,void * data,size_t nbytes,int follow,enum uio_seg pathseg)325 kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace,
326 const char *attrname, void *data, size_t nbytes, int follow,
327 enum uio_seg pathseg)
328 {
329 struct nameidata nd;
330 int error;
331
332 AUDIT_ARG_VALUE(attrnamespace);
333 AUDIT_ARG_TEXT(attrname);
334
335 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
336 error = namei(&nd);
337 if (error)
338 return (error);
339 NDFREE_PNBUF(&nd);
340
341 error = extattr_set_vp(nd.ni_vp, attrnamespace, attrname, data,
342 nbytes, td);
343
344 vrele(nd.ni_vp);
345 return (error);
346 }
347
348 /*-
349 * Get a named extended attribute on a file or directory
350 *
351 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
352 * kernelspace string pointer "attrname", userspace buffer
353 * pointer "data", buffer length "nbytes", thread "td".
354 * Returns: 0 on success, an error number otherwise
355 * Locks: none
356 * References: vp must be a valid reference for the duration of the call
357 */
358 static int
extattr_get_vp(struct vnode * vp,int attrnamespace,const char * attrname,void * data,size_t nbytes,struct thread * td)359 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
360 void *data, size_t nbytes, struct thread *td)
361 {
362 struct uio auio, *auiop;
363 struct iovec aiov;
364 ssize_t cnt;
365 size_t size, *sizep;
366 int error;
367
368 if (nbytes > IOSIZE_MAX)
369 return (EINVAL);
370
371 vn_lock(vp, LK_SHARED | LK_RETRY);
372
373 /*
374 * Slightly unusual semantics: if the user provides a NULL data
375 * pointer, they don't want to receive the data, just the maximum
376 * read length.
377 */
378 auiop = NULL;
379 sizep = NULL;
380 cnt = 0;
381 if (data != NULL) {
382 aiov.iov_base = data;
383 aiov.iov_len = nbytes;
384 auio.uio_iov = &aiov;
385 auio.uio_iovcnt = 1;
386 auio.uio_offset = 0;
387 auio.uio_resid = nbytes;
388 auio.uio_rw = UIO_READ;
389 auio.uio_segflg = UIO_USERSPACE;
390 auio.uio_td = td;
391 auiop = &auio;
392 cnt = nbytes;
393 } else
394 sizep = &size;
395
396 #ifdef MAC
397 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
398 attrname);
399 if (error)
400 goto done;
401 #endif
402
403 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
404 td->td_ucred, td);
405
406 if (auiop != NULL) {
407 cnt -= auio.uio_resid;
408 td->td_retval[0] = cnt;
409 } else
410 td->td_retval[0] = size;
411 #ifdef MAC
412 done:
413 #endif
414 VOP_UNLOCK(vp);
415 return (error);
416 }
417
418 #ifndef _SYS_SYSPROTO_H_
419 struct extattr_get_fd_args {
420 int fd;
421 int attrnamespace;
422 const char *attrname;
423 void *data;
424 size_t nbytes;
425 };
426 #endif
427 int
sys_extattr_get_fd(struct thread * td,struct extattr_get_fd_args * uap)428 sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap)
429 {
430 char attrname[EXTATTR_MAXNAMELEN + 1];
431 int error;
432
433 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
434 if (error)
435 return (error);
436 return (kern_extattr_get_fd(td, uap->fd, uap->attrnamespace,
437 attrname, uap->data, uap->nbytes));
438 }
439
440 int
kern_extattr_get_fp(struct thread * td,struct file * fp,int attrnamespace,const char * attrname,void * data,size_t nbytes)441 kern_extattr_get_fp(struct thread *td, struct file *fp, int attrnamespace,
442 const char *attrname, void *data, size_t nbytes)
443 {
444
445 return (extattr_get_vp(fp->f_vnode, attrnamespace, attrname, data,
446 nbytes, td));
447 }
448
449 int
kern_extattr_get_fd(struct thread * td,int fd,int attrnamespace,const char * attrname,void * data,size_t nbytes)450 kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace,
451 const char *attrname, void *data, size_t nbytes)
452 {
453 struct file *fp;
454 cap_rights_t rights;
455 int error;
456
457 AUDIT_ARG_FD(fd);
458 AUDIT_ARG_VALUE(attrnamespace);
459 AUDIT_ARG_TEXT(attrname);
460
461 error = getvnode_path(td, fd,
462 cap_rights_init_one(&rights, CAP_EXTATTR_GET), NULL, &fp);
463 if (error)
464 return (error);
465
466 error = kern_extattr_get_fp(td, fp, attrnamespace, attrname, data,
467 nbytes);
468
469 fdrop(fp, td);
470 return (error);
471 }
472
473 #ifndef _SYS_SYSPROTO_H_
474 struct extattr_get_file_args {
475 const char *path;
476 int attrnamespace;
477 const char *attrname;
478 void *data;
479 size_t nbytes;
480 };
481 #endif
482 int
sys_extattr_get_file(struct thread * td,struct extattr_get_file_args * uap)483 sys_extattr_get_file(struct thread *td, struct extattr_get_file_args *uap)
484 {
485 return (user_extattr_get_path(td, uap->path, uap->attrnamespace,
486 uap->attrname, uap->data, uap->nbytes, FOLLOW));
487 }
488
489 #ifndef _SYS_SYSPROTO_H_
490 struct extattr_get_link_args {
491 const char *path;
492 int attrnamespace;
493 const char *attrname;
494 void *data;
495 size_t nbytes;
496 };
497 #endif
498 int
sys_extattr_get_link(struct thread * td,struct extattr_get_link_args * uap)499 sys_extattr_get_link(struct thread *td, struct extattr_get_link_args *uap)
500 {
501 return (user_extattr_get_path(td, uap->path, uap->attrnamespace,
502 uap->attrname, uap->data, uap->nbytes, NOFOLLOW));
503 }
504
505 static int
user_extattr_get_path(struct thread * td,const char * path,int attrnamespace,const char * uattrname,void * data,size_t nbytes,int follow)506 user_extattr_get_path(struct thread *td, const char *path, int attrnamespace,
507 const char *uattrname, void *data, size_t nbytes, int follow)
508 {
509 char attrname[EXTATTR_MAXNAMELEN + 1];
510 int error;
511
512 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
513 if (error)
514 return (error);
515 return (kern_extattr_get_path(td, path, attrnamespace,
516 attrname, data, nbytes, follow, UIO_USERSPACE));
517 }
518
519 int
kern_extattr_get_path(struct thread * td,const char * path,int attrnamespace,const char * attrname,void * data,size_t nbytes,int follow,enum uio_seg pathseg)520 kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace,
521 const char *attrname, void *data, size_t nbytes, int follow,
522 enum uio_seg pathseg)
523 {
524 struct nameidata nd;
525 int error;
526
527 AUDIT_ARG_VALUE(attrnamespace);
528 AUDIT_ARG_TEXT(attrname);
529
530 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
531 error = namei(&nd);
532 if (error)
533 return (error);
534 NDFREE_PNBUF(&nd);
535
536 error = extattr_get_vp(nd.ni_vp, attrnamespace, attrname, data,
537 nbytes, td);
538
539 vrele(nd.ni_vp);
540 return (error);
541 }
542
543 /*
544 * extattr_delete_vp(): Delete a named extended attribute on a file or
545 * directory
546 *
547 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
548 * kernelspace string pointer "attrname", proc "p"
549 * Returns: 0 on success, an error number otherwise
550 * Locks: none
551 * References: vp must be a valid reference for the duration of the call
552 */
553 static int
extattr_delete_vp(struct vnode * vp,int attrnamespace,const char * attrname,struct thread * td)554 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
555 struct thread *td)
556 {
557 struct mount *mp;
558 int error;
559
560 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
561 if (error)
562 return (error);
563 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
564
565 #ifdef MAC
566 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
567 attrname);
568 if (error)
569 goto done;
570 #endif
571
572 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
573 td);
574 if (error == EOPNOTSUPP)
575 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
576 td->td_ucred, td);
577 #ifdef MAC
578 done:
579 #endif
580 VOP_UNLOCK(vp);
581 vn_finished_write(mp);
582 return (error);
583 }
584
585 #ifndef _SYS_SYSPROTO_H_
586 struct extattr_delete_fd_args {
587 int fd;
588 int attrnamespace;
589 const char *attrname;
590 };
591 #endif
592 int
sys_extattr_delete_fd(struct thread * td,struct extattr_delete_fd_args * uap)593 sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap)
594 {
595 char attrname[EXTATTR_MAXNAMELEN + 1];
596 int error;
597
598 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
599 if (error)
600 return (error);
601 return (kern_extattr_delete_fd(td, uap->fd, uap->attrnamespace,
602 attrname));
603 }
604
605 int
kern_extattr_delete_fp(struct thread * td,struct file * fp,int attrnamespace,const char * attrname)606 kern_extattr_delete_fp(struct thread *td, struct file *fp, int attrnamespace,
607 const char *attrname)
608 {
609
610 return (extattr_delete_vp(fp->f_vnode, attrnamespace, attrname, td));
611 }
612
613 int
kern_extattr_delete_fd(struct thread * td,int fd,int attrnamespace,const char * attrname)614 kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace,
615 const char *attrname)
616 {
617 struct file *fp;
618 cap_rights_t rights;
619 int error;
620
621 AUDIT_ARG_FD(fd);
622 AUDIT_ARG_VALUE(attrnamespace);
623 AUDIT_ARG_TEXT(attrname);
624
625 error = getvnode_path(td, fd,
626 cap_rights_init_one(&rights, CAP_EXTATTR_DELETE), NULL, &fp);
627 if (error)
628 return (error);
629
630 error = kern_extattr_delete_fp(td, fp, attrnamespace, attrname);
631 fdrop(fp, td);
632 return (error);
633 }
634
635 #ifndef _SYS_SYSPROTO_H_
636 struct extattr_delete_file_args {
637 const char *path;
638 int attrnamespace;
639 const char *attrname;
640 };
641 #endif
642 int
sys_extattr_delete_file(struct thread * td,struct extattr_delete_file_args * uap)643 sys_extattr_delete_file(struct thread *td, struct extattr_delete_file_args *uap)
644 {
645
646 return (user_extattr_delete_path(td, uap->path, uap->attrnamespace,
647 uap->attrname, FOLLOW));
648 }
649
650 #ifndef _SYS_SYSPROTO_H_
651 struct extattr_delete_link_args {
652 const char *path;
653 int attrnamespace;
654 const char *attrname;
655 };
656 #endif
657 int
sys_extattr_delete_link(struct thread * td,struct extattr_delete_link_args * uap)658 sys_extattr_delete_link(struct thread *td, struct extattr_delete_link_args *uap)
659 {
660
661 return (user_extattr_delete_path(td, uap->path, uap->attrnamespace,
662 uap->attrname, NOFOLLOW));
663 }
664
665 int
user_extattr_delete_path(struct thread * td,const char * path,int attrnamespace,const char * uattrname,int follow)666 user_extattr_delete_path(struct thread *td, const char *path, int attrnamespace,
667 const char *uattrname, int follow)
668 {
669 char attrname[EXTATTR_MAXNAMELEN + 1];
670 int error;
671
672 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
673 if (error)
674 return(error);
675 return (kern_extattr_delete_path(td, path, attrnamespace,
676 attrname, follow, UIO_USERSPACE));
677 }
678
679 int
kern_extattr_delete_path(struct thread * td,const char * path,int attrnamespace,const char * attrname,int follow,enum uio_seg pathseg)680 kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace,
681 const char *attrname, int follow, enum uio_seg pathseg)
682 {
683 struct nameidata nd;
684 int error;
685
686 AUDIT_ARG_VALUE(attrnamespace);
687 AUDIT_ARG_TEXT(attrname);
688
689 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
690 error = namei(&nd);
691 if (error)
692 return(error);
693 NDFREE_PNBUF(&nd);
694
695 error = extattr_delete_vp(nd.ni_vp, attrnamespace, attrname, td);
696 vrele(nd.ni_vp);
697 return(error);
698 }
699
700 /*-
701 * Retrieve a list of extended attributes on a file or directory.
702 *
703 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
704 * userspace buffer pointer "data", buffer length "nbytes",
705 * thread "td".
706 * Returns: 0 on success, an error number otherwise
707 * Locks: none
708 * References: vp must be a valid reference for the duration of the call
709 */
710 static int
extattr_list_vp(struct vnode * vp,int attrnamespace,struct uio * auiop,struct thread * td)711 extattr_list_vp(struct vnode *vp, int attrnamespace, struct uio *auiop,
712 struct thread *td)
713 {
714 size_t size, *sizep;
715 ssize_t cnt;
716 int error;
717
718 sizep = NULL;
719 cnt = 0;
720 if (auiop != NULL) {
721 if (auiop->uio_resid > IOSIZE_MAX)
722 return (EINVAL);
723 cnt = auiop->uio_resid;
724 } else
725 sizep = &size;
726
727 vn_lock(vp, LK_SHARED | LK_RETRY);
728
729 #ifdef MAC
730 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
731 if (error) {
732 VOP_UNLOCK(vp);
733 return (error);
734 }
735 #endif
736
737 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
738 td->td_ucred, td);
739 VOP_UNLOCK(vp);
740
741 if (auiop != NULL) {
742 cnt -= auiop->uio_resid;
743 td->td_retval[0] = cnt;
744 } else
745 td->td_retval[0] = size;
746 return (error);
747 }
748
749 #ifndef _SYS_SYSPROTO_H_
750 struct extattr_list_fd_args {
751 int fd;
752 int attrnamespace;
753 void *data;
754 size_t nbytes;
755 };
756 #endif
757 int
sys_extattr_list_fd(struct thread * td,struct extattr_list_fd_args * uap)758 sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap)
759 {
760 struct uio auio, *auiop;
761 struct iovec aiov;
762
763 if (uap->data != NULL) {
764 aiov.iov_base = uap->data;
765 aiov.iov_len = uap->nbytes;
766 auio.uio_iov = &aiov;
767 auio.uio_iovcnt = 1;
768 auio.uio_offset = 0;
769 auio.uio_resid = uap->nbytes;
770 auio.uio_rw = UIO_READ;
771 auio.uio_segflg = UIO_USERSPACE;
772 auio.uio_td = td;
773 auiop = &auio;
774 } else
775 auiop = NULL;
776
777 return (kern_extattr_list_fd(td, uap->fd, uap->attrnamespace,
778 auiop));
779 }
780
781 int
kern_extattr_list_fp(struct thread * td,struct file * fp,int attrnamespace,struct uio * auiop)782 kern_extattr_list_fp(struct thread *td, struct file *fp, int attrnamespace,
783 struct uio *auiop)
784 {
785
786 return (extattr_list_vp(fp->f_vnode, attrnamespace, auiop, td));
787 }
788
789 int
kern_extattr_list_fd(struct thread * td,int fd,int attrnamespace,struct uio * auiop)790 kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace,
791 struct uio *auiop)
792 {
793 struct file *fp;
794 cap_rights_t rights;
795 int error;
796
797 AUDIT_ARG_FD(fd);
798 AUDIT_ARG_VALUE(attrnamespace);
799 error = getvnode_path(td, fd,
800 cap_rights_init_one(&rights, CAP_EXTATTR_LIST), NULL, &fp);
801 if (error)
802 return (error);
803
804 error = kern_extattr_list_fp(td, fp, attrnamespace, auiop);
805
806 fdrop(fp, td);
807 return (error);
808 }
809
810 #ifndef _SYS_SYSPROTO_H_
811 struct extattr_list_file_args {
812 const char *path;
813 int attrnamespace;
814 void *data;
815 size_t nbytes;
816 }
817 #endif
818 int
sys_extattr_list_file(struct thread * td,struct extattr_list_file_args * uap)819 sys_extattr_list_file(struct thread *td, struct extattr_list_file_args *uap)
820 {
821
822 return (user_extattr_list_path(td, uap->path, uap->attrnamespace,
823 uap->data, uap->nbytes, FOLLOW));
824 }
825
826 #ifndef _SYS_SYSPROTO_H_
827 struct extattr_list_link_args {
828 const char *path;
829 int attrnamespace;
830 void *data;
831 size_t nbytes;
832 };
833 #endif
834 int
sys_extattr_list_link(struct thread * td,struct extattr_list_link_args * uap)835 sys_extattr_list_link(struct thread *td, struct extattr_list_link_args *uap)
836 {
837
838 return (user_extattr_list_path(td, uap->path, uap->attrnamespace,
839 uap->data, uap->nbytes, NOFOLLOW));
840 }
841
842 static int
user_extattr_list_path(struct thread * td,const char * path,int attrnamespace,void * data,size_t nbytes,int follow)843 user_extattr_list_path(struct thread *td, const char *path, int attrnamespace,
844 void *data, size_t nbytes, int follow)
845 {
846 struct uio auio, *auiop;
847 struct iovec aiov;
848
849 if (data != NULL) {
850 aiov.iov_base = data;
851 aiov.iov_len = nbytes;
852 auio.uio_iov = &aiov;
853 auio.uio_iovcnt = 1;
854 auio.uio_offset = 0;
855 auio.uio_resid = nbytes;
856 auio.uio_rw = UIO_READ;
857 auio.uio_segflg = UIO_USERSPACE;
858 auio.uio_td = td;
859 auiop = &auio;
860 } else
861 auiop = NULL;
862
863 return (kern_extattr_list_path(td, path, attrnamespace,
864 auiop, follow, UIO_USERSPACE));
865 }
866
867 int
kern_extattr_list_path(struct thread * td,const char * path,int attrnamespace,struct uio * auiop,int follow,enum uio_seg pathseg)868 kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace,
869 struct uio *auiop, int follow, enum uio_seg pathseg)
870 {
871 struct nameidata nd;
872 int error;
873
874 AUDIT_ARG_VALUE(attrnamespace);
875 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
876 error = namei(&nd);
877 if (error)
878 return (error);
879 NDFREE_PNBUF(&nd);
880
881 error = extattr_list_vp(nd.ni_vp, attrnamespace, auiop, td);
882
883 vrele(nd.ni_vp);
884 return (error);
885 }
886