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 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 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 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 244 kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace, 245 const char *attrname, void *data, size_t nbytes) 246 { 247 struct file *fp; 248 cap_rights_t rights; 249 int error; 250 251 AUDIT_ARG_FD(fd); 252 AUDIT_ARG_VALUE(attrnamespace); 253 AUDIT_ARG_TEXT(attrname); 254 255 error = getvnode_path(td, fd, 256 cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp); 257 if (error) 258 return (error); 259 260 error = extattr_set_vp(fp->f_vnode, attrnamespace, 261 attrname, data, nbytes, td); 262 fdrop(fp, td); 263 264 return (error); 265 } 266 267 #ifndef _SYS_SYSPROTO_H_ 268 struct extattr_set_file_args { 269 const char *path; 270 int attrnamespace; 271 const char *attrname; 272 void *data; 273 size_t nbytes; 274 }; 275 #endif 276 int 277 sys_extattr_set_file(struct thread *td, struct extattr_set_file_args *uap) 278 { 279 280 return (user_extattr_set_path(td, uap->path, uap->attrnamespace, 281 uap->attrname, uap->data, uap->nbytes, FOLLOW)); 282 } 283 284 #ifndef _SYS_SYSPROTO_H_ 285 struct extattr_set_link_args { 286 const char *path; 287 int attrnamespace; 288 const char *attrname; 289 void *data; 290 size_t nbytes; 291 }; 292 #endif 293 int 294 sys_extattr_set_link(struct thread *td, struct extattr_set_link_args *uap) 295 { 296 297 return (user_extattr_set_path(td, uap->path, uap->attrnamespace, 298 uap->attrname, uap->data, uap->nbytes, NOFOLLOW)); 299 } 300 301 static int 302 user_extattr_set_path(struct thread *td, const char *path, int attrnamespace, 303 const char *uattrname, void *data, size_t nbytes, int follow) 304 { 305 char attrname[EXTATTR_MAXNAMELEN + 1]; 306 int error; 307 308 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); 309 if (error) 310 return (error); 311 return (kern_extattr_set_path(td, path, attrnamespace, 312 attrname, data, nbytes, follow, UIO_USERSPACE)); 313 } 314 315 int 316 kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace, 317 const char *attrname, void *data, size_t nbytes, int follow, 318 enum uio_seg pathseg) 319 { 320 struct nameidata nd; 321 int error; 322 323 AUDIT_ARG_VALUE(attrnamespace); 324 AUDIT_ARG_TEXT(attrname); 325 326 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); 327 error = namei(&nd); 328 if (error) 329 return (error); 330 NDFREE_PNBUF(&nd); 331 332 error = extattr_set_vp(nd.ni_vp, attrnamespace, attrname, data, 333 nbytes, td); 334 335 vrele(nd.ni_vp); 336 return (error); 337 } 338 339 /*- 340 * Get a named extended attribute on a file or directory 341 * 342 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 343 * kernelspace string pointer "attrname", userspace buffer 344 * pointer "data", buffer length "nbytes", thread "td". 345 * Returns: 0 on success, an error number otherwise 346 * Locks: none 347 * References: vp must be a valid reference for the duration of the call 348 */ 349 static int 350 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 351 void *data, size_t nbytes, struct thread *td) 352 { 353 struct uio auio, *auiop; 354 struct iovec aiov; 355 ssize_t cnt; 356 size_t size, *sizep; 357 int error; 358 359 if (nbytes > IOSIZE_MAX) 360 return (EINVAL); 361 362 vn_lock(vp, LK_SHARED | LK_RETRY); 363 364 /* 365 * Slightly unusual semantics: if the user provides a NULL data 366 * pointer, they don't want to receive the data, just the maximum 367 * read length. 368 */ 369 auiop = NULL; 370 sizep = NULL; 371 cnt = 0; 372 if (data != NULL) { 373 aiov.iov_base = data; 374 aiov.iov_len = nbytes; 375 auio.uio_iov = &aiov; 376 auio.uio_iovcnt = 1; 377 auio.uio_offset = 0; 378 auio.uio_resid = nbytes; 379 auio.uio_rw = UIO_READ; 380 auio.uio_segflg = UIO_USERSPACE; 381 auio.uio_td = td; 382 auiop = &auio; 383 cnt = nbytes; 384 } else 385 sizep = &size; 386 387 #ifdef MAC 388 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace, 389 attrname); 390 if (error) 391 goto done; 392 #endif 393 394 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, 395 td->td_ucred, td); 396 397 if (auiop != NULL) { 398 cnt -= auio.uio_resid; 399 td->td_retval[0] = cnt; 400 } else 401 td->td_retval[0] = size; 402 #ifdef MAC 403 done: 404 #endif 405 VOP_UNLOCK(vp); 406 return (error); 407 } 408 409 #ifndef _SYS_SYSPROTO_H_ 410 struct extattr_get_fd_args { 411 int fd; 412 int attrnamespace; 413 const char *attrname; 414 void *data; 415 size_t nbytes; 416 }; 417 #endif 418 int 419 sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap) 420 { 421 char attrname[EXTATTR_MAXNAMELEN + 1]; 422 int error; 423 424 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); 425 if (error) 426 return (error); 427 return (kern_extattr_get_fd(td, uap->fd, uap->attrnamespace, 428 attrname, uap->data, uap->nbytes)); 429 } 430 431 int 432 kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace, 433 const char *attrname, void *data, size_t nbytes) 434 { 435 struct file *fp; 436 cap_rights_t rights; 437 int error; 438 439 AUDIT_ARG_FD(fd); 440 AUDIT_ARG_VALUE(attrnamespace); 441 AUDIT_ARG_TEXT(attrname); 442 443 error = getvnode_path(td, fd, 444 cap_rights_init_one(&rights, CAP_EXTATTR_GET), &fp); 445 if (error) 446 return (error); 447 448 error = extattr_get_vp(fp->f_vnode, attrnamespace, 449 attrname, data, nbytes, td); 450 451 fdrop(fp, td); 452 return (error); 453 } 454 455 #ifndef _SYS_SYSPROTO_H_ 456 struct extattr_get_file_args { 457 const char *path; 458 int attrnamespace; 459 const char *attrname; 460 void *data; 461 size_t nbytes; 462 }; 463 #endif 464 int 465 sys_extattr_get_file(struct thread *td, struct extattr_get_file_args *uap) 466 { 467 return (user_extattr_get_path(td, uap->path, uap->attrnamespace, 468 uap->attrname, uap->data, uap->nbytes, FOLLOW)); 469 } 470 471 #ifndef _SYS_SYSPROTO_H_ 472 struct extattr_get_link_args { 473 const char *path; 474 int attrnamespace; 475 const char *attrname; 476 void *data; 477 size_t nbytes; 478 }; 479 #endif 480 int 481 sys_extattr_get_link(struct thread *td, struct extattr_get_link_args *uap) 482 { 483 return (user_extattr_get_path(td, uap->path, uap->attrnamespace, 484 uap->attrname, uap->data, uap->nbytes, NOFOLLOW)); 485 } 486 487 static int 488 user_extattr_get_path(struct thread *td, const char *path, int attrnamespace, 489 const char *uattrname, void *data, size_t nbytes, int follow) 490 { 491 char attrname[EXTATTR_MAXNAMELEN + 1]; 492 int error; 493 494 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); 495 if (error) 496 return (error); 497 return (kern_extattr_get_path(td, path, attrnamespace, 498 attrname, data, nbytes, follow, UIO_USERSPACE)); 499 } 500 501 int 502 kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace, 503 const char *attrname, void *data, size_t nbytes, int follow, 504 enum uio_seg pathseg) 505 { 506 struct nameidata nd; 507 int error; 508 509 AUDIT_ARG_VALUE(attrnamespace); 510 AUDIT_ARG_TEXT(attrname); 511 512 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); 513 error = namei(&nd); 514 if (error) 515 return (error); 516 NDFREE_PNBUF(&nd); 517 518 error = extattr_get_vp(nd.ni_vp, attrnamespace, attrname, data, 519 nbytes, td); 520 521 vrele(nd.ni_vp); 522 return (error); 523 } 524 525 /* 526 * extattr_delete_vp(): Delete a named extended attribute on a file or 527 * directory 528 * 529 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 530 * kernelspace string pointer "attrname", proc "p" 531 * Returns: 0 on success, an error number otherwise 532 * Locks: none 533 * References: vp must be a valid reference for the duration of the call 534 */ 535 static int 536 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 537 struct thread *td) 538 { 539 struct mount *mp; 540 int error; 541 542 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); 543 if (error) 544 return (error); 545 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 546 547 #ifdef MAC 548 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace, 549 attrname); 550 if (error) 551 goto done; 552 #endif 553 554 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred, 555 td); 556 if (error == EOPNOTSUPP) 557 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 558 td->td_ucred, td); 559 #ifdef MAC 560 done: 561 #endif 562 VOP_UNLOCK(vp); 563 vn_finished_write(mp); 564 return (error); 565 } 566 567 #ifndef _SYS_SYSPROTO_H_ 568 struct extattr_delete_fd_args { 569 int fd; 570 int attrnamespace; 571 const char *attrname; 572 }; 573 #endif 574 int 575 sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap) 576 { 577 char attrname[EXTATTR_MAXNAMELEN + 1]; 578 int error; 579 580 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); 581 if (error) 582 return (error); 583 return (kern_extattr_delete_fd(td, uap->fd, uap->attrnamespace, 584 attrname)); 585 } 586 587 int 588 kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace, 589 const char *attrname) 590 { 591 struct file *fp; 592 cap_rights_t rights; 593 int error; 594 595 AUDIT_ARG_FD(fd); 596 AUDIT_ARG_VALUE(attrnamespace); 597 AUDIT_ARG_TEXT(attrname); 598 599 error = getvnode_path(td, fd, 600 cap_rights_init_one(&rights, CAP_EXTATTR_DELETE), &fp); 601 if (error) 602 return (error); 603 604 error = extattr_delete_vp(fp->f_vnode, attrnamespace, 605 attrname, td); 606 fdrop(fp, td); 607 return (error); 608 } 609 610 #ifndef _SYS_SYSPROTO_H_ 611 struct extattr_delete_file_args { 612 const char *path; 613 int attrnamespace; 614 const char *attrname; 615 }; 616 #endif 617 int 618 sys_extattr_delete_file(struct thread *td, struct extattr_delete_file_args *uap) 619 { 620 621 return (user_extattr_delete_path(td, uap->path, uap->attrnamespace, 622 uap->attrname, FOLLOW)); 623 } 624 625 #ifndef _SYS_SYSPROTO_H_ 626 struct extattr_delete_link_args { 627 const char *path; 628 int attrnamespace; 629 const char *attrname; 630 }; 631 #endif 632 int 633 sys_extattr_delete_link(struct thread *td, struct extattr_delete_link_args *uap) 634 { 635 636 return (user_extattr_delete_path(td, uap->path, uap->attrnamespace, 637 uap->attrname, NOFOLLOW)); 638 } 639 640 int 641 user_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, 642 const char *uattrname, int follow) 643 { 644 char attrname[EXTATTR_MAXNAMELEN + 1]; 645 int error; 646 647 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); 648 if (error) 649 return(error); 650 return (kern_extattr_delete_path(td, path, attrnamespace, 651 attrname, follow, UIO_USERSPACE)); 652 } 653 654 int 655 kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, 656 const char *attrname, int follow, enum uio_seg pathseg) 657 { 658 struct nameidata nd; 659 int error; 660 661 AUDIT_ARG_VALUE(attrnamespace); 662 AUDIT_ARG_TEXT(attrname); 663 664 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); 665 error = namei(&nd); 666 if (error) 667 return(error); 668 NDFREE_PNBUF(&nd); 669 670 error = extattr_delete_vp(nd.ni_vp, attrnamespace, attrname, td); 671 vrele(nd.ni_vp); 672 return(error); 673 } 674 675 /*- 676 * Retrieve a list of extended attributes on a file or directory. 677 * 678 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace", 679 * userspace buffer pointer "data", buffer length "nbytes", 680 * thread "td". 681 * Returns: 0 on success, an error number otherwise 682 * Locks: none 683 * References: vp must be a valid reference for the duration of the call 684 */ 685 static int 686 extattr_list_vp(struct vnode *vp, int attrnamespace, struct uio *auiop, 687 struct thread *td) 688 { 689 size_t size, *sizep; 690 ssize_t cnt; 691 int error; 692 693 sizep = NULL; 694 cnt = 0; 695 if (auiop != NULL) { 696 if (auiop->uio_resid > IOSIZE_MAX) 697 return (EINVAL); 698 cnt = auiop->uio_resid; 699 } else 700 sizep = &size; 701 702 vn_lock(vp, LK_SHARED | LK_RETRY); 703 704 #ifdef MAC 705 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace); 706 if (error) { 707 VOP_UNLOCK(vp); 708 return (error); 709 } 710 #endif 711 712 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, 713 td->td_ucred, td); 714 VOP_UNLOCK(vp); 715 716 if (auiop != NULL) { 717 cnt -= auiop->uio_resid; 718 td->td_retval[0] = cnt; 719 } else 720 td->td_retval[0] = size; 721 return (error); 722 } 723 724 #ifndef _SYS_SYSPROTO_H_ 725 struct extattr_list_fd_args { 726 int fd; 727 int attrnamespace; 728 void *data; 729 size_t nbytes; 730 }; 731 #endif 732 int 733 sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap) 734 { 735 struct uio auio, *auiop; 736 struct iovec aiov; 737 738 if (uap->data != NULL) { 739 aiov.iov_base = uap->data; 740 aiov.iov_len = uap->nbytes; 741 auio.uio_iov = &aiov; 742 auio.uio_iovcnt = 1; 743 auio.uio_offset = 0; 744 auio.uio_resid = uap->nbytes; 745 auio.uio_rw = UIO_READ; 746 auio.uio_segflg = UIO_USERSPACE; 747 auio.uio_td = td; 748 auiop = &auio; 749 } else 750 auiop = NULL; 751 752 return (kern_extattr_list_fd(td, uap->fd, uap->attrnamespace, 753 auiop)); 754 } 755 756 int 757 kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace, 758 struct uio *auiop) 759 { 760 struct file *fp; 761 cap_rights_t rights; 762 int error; 763 764 AUDIT_ARG_FD(fd); 765 AUDIT_ARG_VALUE(attrnamespace); 766 error = getvnode_path(td, fd, 767 cap_rights_init_one(&rights, CAP_EXTATTR_LIST), &fp); 768 if (error) 769 return (error); 770 771 error = extattr_list_vp(fp->f_vnode, attrnamespace, auiop, td); 772 773 fdrop(fp, td); 774 return (error); 775 } 776 777 #ifndef _SYS_SYSPROTO_H_ 778 struct extattr_list_file_args { 779 const char *path; 780 int attrnamespace; 781 void *data; 782 size_t nbytes; 783 } 784 #endif 785 int 786 sys_extattr_list_file(struct thread *td, struct extattr_list_file_args *uap) 787 { 788 789 return (user_extattr_list_path(td, uap->path, uap->attrnamespace, 790 uap->data, uap->nbytes, FOLLOW)); 791 } 792 793 #ifndef _SYS_SYSPROTO_H_ 794 struct extattr_list_link_args { 795 const char *path; 796 int attrnamespace; 797 void *data; 798 size_t nbytes; 799 }; 800 #endif 801 int 802 sys_extattr_list_link(struct thread *td, struct extattr_list_link_args *uap) 803 { 804 805 return (user_extattr_list_path(td, uap->path, uap->attrnamespace, 806 uap->data, uap->nbytes, NOFOLLOW)); 807 } 808 809 static int 810 user_extattr_list_path(struct thread *td, const char *path, int attrnamespace, 811 void *data, size_t nbytes, int follow) 812 { 813 struct uio auio, *auiop; 814 struct iovec aiov; 815 816 if (data != NULL) { 817 aiov.iov_base = data; 818 aiov.iov_len = nbytes; 819 auio.uio_iov = &aiov; 820 auio.uio_iovcnt = 1; 821 auio.uio_offset = 0; 822 auio.uio_resid = nbytes; 823 auio.uio_rw = UIO_READ; 824 auio.uio_segflg = UIO_USERSPACE; 825 auio.uio_td = td; 826 auiop = &auio; 827 } else 828 auiop = NULL; 829 830 return (kern_extattr_list_path(td, path, attrnamespace, 831 auiop, follow, UIO_USERSPACE)); 832 } 833 834 int 835 kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace, 836 struct uio *auiop, int follow, enum uio_seg pathseg) 837 { 838 struct nameidata nd; 839 int error; 840 841 AUDIT_ARG_VALUE(attrnamespace); 842 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); 843 error = namei(&nd); 844 if (error) 845 return (error); 846 NDFREE_PNBUF(&nd); 847 848 error = extattr_list_vp(nd.ni_vp, attrnamespace, auiop, td); 849 850 vrele(nd.ni_vp); 851 return (error); 852 } 853