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 50static 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); 53static 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); 56static int user_extattr_delete_path(struct thread *td, const char *path, 57 int attrnamespace, const char *attrname, int follow); 58static 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_ 69struct extattrctl_args { 70 const char *path; 71 int cmd; 72 const char *filename; 73 int attrnamespace; 74 const char *attrname; 75}; 76#endif 77int 78sys_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); 149out: 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 */ 172static int 173extattr_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 214done: 215#endif 216 VOP_UNLOCK(vp); 217 vn_finished_write(mp); 218 return (error); 219} 220 221#ifndef _SYS_SYSPROTO_H_ 222struct extattr_set_fd_args { 223 int fd; 224 int attrnamespace; 225 const char *attrname; 226 void *data; 227 size_t nbytes; 228}; 229#endif 230int 231sys_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 243int 244kern_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_ 268struct 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 276int 277sys_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_ 285struct 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 293int 294sys_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 301static int 302user_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 315int 316kern_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 */ 349static int 350extattr_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 403done: 404#endif 405 VOP_UNLOCK(vp); 406 return (error); 407} 408 409#ifndef _SYS_SYSPROTO_H_ 410struct extattr_get_fd_args { 411 int fd; 412 int attrnamespace; 413 const char *attrname; 414 void *data; 415 size_t nbytes; 416}; 417#endif 418int 419sys_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 431int 432kern_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_ 456struct 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 464int 465sys_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_ 472struct 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 480int 481sys_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 487static int 488user_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 501int 502kern_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 */ 535static int 536extattr_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 560done: 561#endif 562 VOP_UNLOCK(vp); 563 vn_finished_write(mp); 564 return (error); 565} 566 567#ifndef _SYS_SYSPROTO_H_ 568struct extattr_delete_fd_args { 569 int fd; 570 int attrnamespace; 571 const char *attrname; 572}; 573#endif 574int 575sys_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 587int 588kern_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_ 611struct extattr_delete_file_args { 612 const char *path; 613 int attrnamespace; 614 const char *attrname; 615}; 616#endif 617int 618sys_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_ 626struct extattr_delete_link_args { 627 const char *path; 628 int attrnamespace; 629 const char *attrname; 630}; 631#endif 632int 633sys_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 640int 641user_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 654int 655kern_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 */ 685static int 686extattr_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_ 725struct extattr_list_fd_args { 726 int fd; 727 int attrnamespace; 728 void *data; 729 size_t nbytes; 730}; 731#endif 732int 733sys_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 756int 757kern_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_ 778struct extattr_list_file_args { 779 const char *path; 780 int attrnamespace; 781 void *data; 782 size_t nbytes; 783} 784#endif 785int 786sys_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_ 794struct extattr_list_link_args { 795 const char *path; 796 int attrnamespace; 797 void *data; 798 size_t nbytes; 799}; 800#endif 801int 802sys_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 809static int 810user_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 834int 835kern_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