40#include <sys/namei.h> 41#include <sys/filedesc.h> 42#include <sys/limits.h> 43#include <sys/vnode.h> 44#include <sys/proc.h> 45#include <sys/extattr.h> 46 47#include <security/audit/audit.h> 48#include <security/mac/mac_framework.h> 49 50/* 51 * Syscall to push extended attribute configuration information into the VFS. 52 * Accepts a path, which it converts to a mountpoint, as well as a command 53 * (int cmd), and attribute name and misc data. 54 * 55 * Currently this is used only by UFS1 extended attributes. 56 */ 57int 58extattrctl(td, uap) 59 struct thread *td; 60 struct extattrctl_args /* { 61 const char *path; 62 int cmd; 63 const char *filename; 64 int attrnamespace; 65 const char *attrname; 66 } */ *uap; 67{ 68 struct vnode *filename_vp; 69 struct nameidata nd; 70 struct mount *mp, *mp_writable; 71 char attrname[EXTATTR_MAXNAMELEN]; 72 int vfslocked, fnvfslocked, error; 73 74 AUDIT_ARG(cmd, uap->cmd); 75 AUDIT_ARG(value, uap->attrnamespace); 76 /* 77 * uap->attrname is not always defined. We check again later when we 78 * invoke the VFS call so as to pass in NULL there if needed. 79 */ 80 if (uap->attrname != NULL) { 81 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, 82 NULL); 83 if (error) 84 return (error); 85 } 86 AUDIT_ARG(text, attrname); 87 88 vfslocked = fnvfslocked = 0; 89 /* 90 * uap->filename is not always defined. If it is, grab a vnode lock, 91 * which VFS_EXTATTRCTL() will later release. 92 */ 93 filename_vp = NULL; 94 if (uap->filename != NULL) { 95 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF | 96 AUDITVNODE2, UIO_USERSPACE, uap->filename, td); 97 error = namei(&nd); 98 if (error) 99 return (error); 100 fnvfslocked = NDHASGIANT(&nd); 101 filename_vp = nd.ni_vp; 102 NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK); 103 } 104 105 /* uap->path is always defined. */ 106 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 107 uap->path, td); 108 error = namei(&nd); 109 if (error) { 110 if (filename_vp != NULL) 111 vput(filename_vp); 112 goto out; 113 } 114 vfslocked = NDHASGIANT(&nd); 115 mp = nd.ni_vp->v_mount; 116 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH); 117 NDFREE(&nd, 0); 118 if (error) { 119 if (filename_vp != NULL) 120 vput(filename_vp); 121 goto out; 122 } 123 124 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace, 125 uap->attrname != NULL ? attrname : NULL, td); 126 127 vn_finished_write(mp_writable); 128 /* 129 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp, 130 * so vrele it if it is defined. 131 */ 132 if (filename_vp != NULL) 133 vrele(filename_vp); 134out: 135 VFS_UNLOCK_GIANT(fnvfslocked); 136 VFS_UNLOCK_GIANT(vfslocked); 137 return (error); 138} 139 140/*- 141 * Set a named extended attribute on a file or directory 142 * 143 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 144 * kernelspace string pointer "attrname", userspace buffer 145 * pointer "data", buffer length "nbytes", thread "td". 146 * Returns: 0 on success, an error number otherwise 147 * Locks: none 148 * References: vp must be a valid reference for the duration of the call 149 */ 150static int 151extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 152 void *data, size_t nbytes, struct thread *td) 153{ 154 struct mount *mp; 155 struct uio auio; 156 struct iovec aiov; 157 ssize_t cnt; 158 int error; 159 160 VFS_ASSERT_GIANT(vp->v_mount); 161 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 162 if (error) 163 return (error); 164 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 165 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 166 167 aiov.iov_base = data; 168 aiov.iov_len = nbytes; 169 auio.uio_iov = &aiov; 170 auio.uio_iovcnt = 1; 171 auio.uio_offset = 0; 172 if (nbytes > INT_MAX) { 173 error = EINVAL; 174 goto done; 175 } 176 auio.uio_resid = nbytes; 177 auio.uio_rw = UIO_WRITE; 178 auio.uio_segflg = UIO_USERSPACE; 179 auio.uio_td = td; 180 cnt = nbytes; 181 182#ifdef MAC 183 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace, 184 attrname, &auio); 185 if (error) 186 goto done; 187#endif 188 189 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, 190 td->td_ucred, td); 191 cnt -= auio.uio_resid; 192 td->td_retval[0] = cnt; 193 194done: 195 VOP_UNLOCK(vp, 0); 196 vn_finished_write(mp); 197 return (error); 198} 199 200int 201extattr_set_fd(td, uap) 202 struct thread *td; 203 struct extattr_set_fd_args /* { 204 int fd; 205 int attrnamespace; 206 const char *attrname; 207 void *data; 208 size_t nbytes; 209 } */ *uap; 210{ 211 struct file *fp; 212 char attrname[EXTATTR_MAXNAMELEN]; 213 int vfslocked, error; 214 215 AUDIT_ARG(fd, uap->fd); 216 AUDIT_ARG(value, uap->attrnamespace); 217 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 218 if (error) 219 return (error); 220 AUDIT_ARG(text, attrname); 221 222 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 223 if (error) 224 return (error); 225 226 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 227 error = extattr_set_vp(fp->f_vnode, uap->attrnamespace, 228 attrname, uap->data, uap->nbytes, td); 229 fdrop(fp, td); 230 VFS_UNLOCK_GIANT(vfslocked); 231 232 return (error); 233} 234 235int 236extattr_set_file(td, uap) 237 struct thread *td; 238 struct extattr_set_file_args /* { 239 const char *path; 240 int attrnamespace; 241 const char *attrname; 242 void *data; 243 size_t nbytes; 244 } */ *uap; 245{ 246 struct nameidata nd; 247 char attrname[EXTATTR_MAXNAMELEN]; 248 int vfslocked, error; 249 250 AUDIT_ARG(value, uap->attrnamespace); 251 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 252 if (error) 253 return (error); 254 AUDIT_ARG(text, attrname); 255 256 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 257 uap->path, td); 258 error = namei(&nd); 259 if (error) 260 return (error); 261 NDFREE(&nd, NDF_ONLY_PNBUF); 262 263 vfslocked = NDHASGIANT(&nd); 264 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, 265 uap->data, uap->nbytes, td); 266 267 vrele(nd.ni_vp); 268 VFS_UNLOCK_GIANT(vfslocked); 269 return (error); 270} 271 272int 273extattr_set_link(td, uap) 274 struct thread *td; 275 struct extattr_set_link_args /* { 276 const char *path; 277 int attrnamespace; 278 const char *attrname; 279 void *data; 280 size_t nbytes; 281 } */ *uap; 282{ 283 struct nameidata nd; 284 char attrname[EXTATTR_MAXNAMELEN]; 285 int vfslocked, error; 286 287 AUDIT_ARG(value, uap->attrnamespace); 288 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 289 if (error) 290 return (error); 291 AUDIT_ARG(text, attrname); 292 293 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 294 uap->path, td); 295 error = namei(&nd); 296 if (error) 297 return (error); 298 NDFREE(&nd, NDF_ONLY_PNBUF); 299 300 vfslocked = NDHASGIANT(&nd); 301 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, 302 uap->data, uap->nbytes, td); 303 304 vrele(nd.ni_vp); 305 VFS_UNLOCK_GIANT(vfslocked); 306 return (error); 307} 308 309/*- 310 * Get a named extended attribute on a file or directory 311 * 312 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 313 * kernelspace string pointer "attrname", userspace buffer 314 * pointer "data", buffer length "nbytes", thread "td". 315 * Returns: 0 on success, an error number otherwise 316 * Locks: none 317 * References: vp must be a valid reference for the duration of the call 318 */ 319static int 320extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 321 void *data, size_t nbytes, struct thread *td) 322{ 323 struct uio auio, *auiop; 324 struct iovec aiov; 325 ssize_t cnt; 326 size_t size, *sizep; 327 int error; 328 329 VFS_ASSERT_GIANT(vp->v_mount); 330 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ); 331 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 332 333 /* 334 * Slightly unusual semantics: if the user provides a NULL data 335 * pointer, they don't want to receive the data, just the maximum 336 * read length. 337 */ 338 auiop = NULL; 339 sizep = NULL; 340 cnt = 0; 341 if (data != NULL) { 342 aiov.iov_base = data; 343 aiov.iov_len = nbytes; 344 auio.uio_iov = &aiov; 345 auio.uio_iovcnt = 1; 346 auio.uio_offset = 0; 347 if (nbytes > INT_MAX) { 348 error = EINVAL; 349 goto done; 350 } 351 auio.uio_resid = nbytes; 352 auio.uio_rw = UIO_READ; 353 auio.uio_segflg = UIO_USERSPACE; 354 auio.uio_td = td; 355 auiop = &auio; 356 cnt = nbytes; 357 } else 358 sizep = &size; 359 360#ifdef MAC 361 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace, 362 attrname, &auio); 363 if (error) 364 goto done; 365#endif 366 367 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, 368 td->td_ucred, td); 369 370 if (auiop != NULL) { 371 cnt -= auio.uio_resid; 372 td->td_retval[0] = cnt; 373 } else 374 td->td_retval[0] = size; 375 376done: 377 VOP_UNLOCK(vp, 0); 378 return (error); 379} 380 381int 382extattr_get_fd(td, uap) 383 struct thread *td; 384 struct extattr_get_fd_args /* { 385 int fd; 386 int attrnamespace; 387 const char *attrname; 388 void *data; 389 size_t nbytes; 390 } */ *uap; 391{ 392 struct file *fp; 393 char attrname[EXTATTR_MAXNAMELEN]; 394 int vfslocked, error; 395 396 AUDIT_ARG(fd, uap->fd); 397 AUDIT_ARG(value, uap->attrnamespace); 398 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 399 if (error) 400 return (error); 401 AUDIT_ARG(text, attrname); 402 403 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 404 if (error) 405 return (error); 406 407 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 408 error = extattr_get_vp(fp->f_vnode, uap->attrnamespace, 409 attrname, uap->data, uap->nbytes, td); 410 411 fdrop(fp, td); 412 VFS_UNLOCK_GIANT(vfslocked); 413 return (error); 414} 415 416int 417extattr_get_file(td, uap) 418 struct thread *td; 419 struct extattr_get_file_args /* { 420 const char *path; 421 int attrnamespace; 422 const char *attrname; 423 void *data; 424 size_t nbytes; 425 } */ *uap; 426{ 427 struct nameidata nd; 428 char attrname[EXTATTR_MAXNAMELEN]; 429 int vfslocked, error; 430 431 AUDIT_ARG(value, uap->attrnamespace); 432 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 433 if (error) 434 return (error); 435 AUDIT_ARG(text, attrname); 436 437 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 438 uap->path, td); 439 error = namei(&nd); 440 if (error) 441 return (error); 442 NDFREE(&nd, NDF_ONLY_PNBUF); 443 444 vfslocked = NDHASGIANT(&nd); 445 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, 446 uap->data, uap->nbytes, td); 447 448 vrele(nd.ni_vp); 449 VFS_UNLOCK_GIANT(vfslocked); 450 return (error); 451} 452 453int 454extattr_get_link(td, uap) 455 struct thread *td; 456 struct extattr_get_link_args /* { 457 const char *path; 458 int attrnamespace; 459 const char *attrname; 460 void *data; 461 size_t nbytes; 462 } */ *uap; 463{ 464 struct nameidata nd; 465 char attrname[EXTATTR_MAXNAMELEN]; 466 int vfslocked, error; 467 468 AUDIT_ARG(value, uap->attrnamespace); 469 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 470 if (error) 471 return (error); 472 AUDIT_ARG(text, attrname); 473 474 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 475 uap->path, td); 476 error = namei(&nd); 477 if (error) 478 return (error); 479 NDFREE(&nd, NDF_ONLY_PNBUF); 480 481 vfslocked = NDHASGIANT(&nd); 482 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, 483 uap->data, uap->nbytes, td); 484 485 vrele(nd.ni_vp); 486 VFS_UNLOCK_GIANT(vfslocked); 487 return (error); 488} 489 490/* 491 * extattr_delete_vp(): Delete a named extended attribute on a file or 492 * directory 493 * 494 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 495 * kernelspace string pointer "attrname", proc "p" 496 * Returns: 0 on success, an error number otherwise 497 * Locks: none 498 * References: vp must be a valid reference for the duration of the call 499 */ 500static int 501extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 502 struct thread *td) 503{ 504 struct mount *mp; 505 int error; 506 507 VFS_ASSERT_GIANT(vp->v_mount); 508 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 509 if (error) 510 return (error); 511 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 512 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 513 514#ifdef MAC 515 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace, 516 attrname); 517 if (error) 518 goto done; 519#endif 520 521 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred, 522 td); 523 if (error == EOPNOTSUPP) 524 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 525 td->td_ucred, td); 526#ifdef MAC 527done: 528#endif 529 VOP_UNLOCK(vp, 0); 530 vn_finished_write(mp); 531 return (error); 532} 533 534int 535extattr_delete_fd(td, uap) 536 struct thread *td; 537 struct extattr_delete_fd_args /* { 538 int fd; 539 int attrnamespace; 540 const char *attrname; 541 } */ *uap; 542{ 543 struct file *fp; 544 char attrname[EXTATTR_MAXNAMELEN]; 545 int vfslocked, error; 546 547 AUDIT_ARG(fd, uap->fd); 548 AUDIT_ARG(value, uap->attrnamespace); 549 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 550 if (error) 551 return (error); 552 AUDIT_ARG(text, attrname); 553 554 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 555 if (error) 556 return (error); 557 558 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 559 error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace, 560 attrname, td); 561 fdrop(fp, td); 562 VFS_UNLOCK_GIANT(vfslocked); 563 return (error); 564} 565 566int 567extattr_delete_file(td, uap) 568 struct thread *td; 569 struct extattr_delete_file_args /* { 570 const char *path; 571 int attrnamespace; 572 const char *attrname; 573 } */ *uap; 574{ 575 struct nameidata nd; 576 char attrname[EXTATTR_MAXNAMELEN]; 577 int vfslocked, error; 578 579 AUDIT_ARG(value, uap->attrnamespace); 580 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 581 if (error) 582 return(error); 583 AUDIT_ARG(text, attrname); 584 585 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 586 uap->path, td); 587 error = namei(&nd); 588 if (error) 589 return(error); 590 NDFREE(&nd, NDF_ONLY_PNBUF); 591 592 vfslocked = NDHASGIANT(&nd); 593 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td); 594 vrele(nd.ni_vp); 595 VFS_UNLOCK_GIANT(vfslocked); 596 return(error); 597} 598 599int 600extattr_delete_link(td, uap) 601 struct thread *td; 602 struct extattr_delete_link_args /* { 603 const char *path; 604 int attrnamespace; 605 const char *attrname; 606 } */ *uap; 607{ 608 struct nameidata nd; 609 char attrname[EXTATTR_MAXNAMELEN]; 610 int vfslocked, error; 611 612 AUDIT_ARG(value, uap->attrnamespace); 613 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 614 if (error) 615 return(error); 616 AUDIT_ARG(text, attrname); 617 618 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 619 uap->path, td); 620 error = namei(&nd); 621 if (error) 622 return(error); 623 NDFREE(&nd, NDF_ONLY_PNBUF); 624 625 vfslocked = NDHASGIANT(&nd); 626 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td); 627 vrele(nd.ni_vp); 628 VFS_UNLOCK_GIANT(vfslocked); 629 return(error); 630} 631 632/*- 633 * Retrieve a list of extended attributes on a file or directory. 634 * 635 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace", 636 * userspace buffer pointer "data", buffer length "nbytes", 637 * thread "td". 638 * Returns: 0 on success, an error number otherwise 639 * Locks: none 640 * References: vp must be a valid reference for the duration of the call 641 */ 642static int 643extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, 644 size_t nbytes, struct thread *td) 645{ 646 struct uio auio, *auiop; 647 size_t size, *sizep; 648 struct iovec aiov; 649 ssize_t cnt; 650 int error; 651 652 VFS_ASSERT_GIANT(vp->v_mount); 653 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ); 654 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 655 656 auiop = NULL; 657 sizep = NULL; 658 cnt = 0; 659 if (data != NULL) { 660 aiov.iov_base = data; 661 aiov.iov_len = nbytes; 662 auio.uio_iov = &aiov; 663 auio.uio_iovcnt = 1; 664 auio.uio_offset = 0; 665 if (nbytes > INT_MAX) { 666 error = EINVAL; 667 goto done; 668 } 669 auio.uio_resid = nbytes; 670 auio.uio_rw = UIO_READ; 671 auio.uio_segflg = UIO_USERSPACE; 672 auio.uio_td = td; 673 auiop = &auio; 674 cnt = nbytes; 675 } else 676 sizep = &size; 677 678#ifdef MAC 679 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace); 680 if (error) 681 goto done; 682#endif 683 684 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, 685 td->td_ucred, td); 686 687 if (auiop != NULL) { 688 cnt -= auio.uio_resid; 689 td->td_retval[0] = cnt; 690 } else 691 td->td_retval[0] = size; 692 693done: 694 VOP_UNLOCK(vp, 0); 695 return (error); 696} 697 698 699int 700extattr_list_fd(td, uap) 701 struct thread *td; 702 struct extattr_list_fd_args /* { 703 int fd; 704 int attrnamespace; 705 void *data; 706 size_t nbytes; 707 } */ *uap; 708{ 709 struct file *fp; 710 int vfslocked, error; 711 712 AUDIT_ARG(fd, uap->fd); 713 AUDIT_ARG(value, uap->attrnamespace); 714 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 715 if (error) 716 return (error); 717 718 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 719 error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data, 720 uap->nbytes, td); 721 722 fdrop(fp, td); 723 VFS_UNLOCK_GIANT(vfslocked); 724 return (error); 725} 726 727int 728extattr_list_file(td, uap) 729 struct thread*td; 730 struct extattr_list_file_args /* { 731 const char *path; 732 int attrnamespace; 733 void *data; 734 size_t nbytes; 735 } */ *uap; 736{ 737 struct nameidata nd; 738 int vfslocked, error; 739 740 AUDIT_ARG(value, uap->attrnamespace); 741 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 742 uap->path, td); 743 error = namei(&nd); 744 if (error) 745 return (error); 746 NDFREE(&nd, NDF_ONLY_PNBUF); 747 748 vfslocked = NDHASGIANT(&nd); 749 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, 750 uap->nbytes, td); 751 752 vrele(nd.ni_vp); 753 VFS_UNLOCK_GIANT(vfslocked); 754 return (error); 755} 756 757int 758extattr_list_link(td, uap) 759 struct thread*td; 760 struct extattr_list_link_args /* { 761 const char *path; 762 int attrnamespace; 763 void *data; 764 size_t nbytes; 765 } */ *uap; 766{ 767 struct nameidata nd; 768 int vfslocked, error; 769 770 AUDIT_ARG(value, uap->attrnamespace); 771 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 772 uap->path, td); 773 error = namei(&nd); 774 if (error) 775 return (error); 776 NDFREE(&nd, NDF_ONLY_PNBUF); 777 778 vfslocked = NDHASGIANT(&nd); 779 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, 780 uap->nbytes, td); 781 782 vrele(nd.ni_vp); 783 VFS_UNLOCK_GIANT(vfslocked); 784 return (error); 785}
| 41#include <sys/namei.h> 42#include <sys/filedesc.h> 43#include <sys/limits.h> 44#include <sys/vnode.h> 45#include <sys/proc.h> 46#include <sys/extattr.h> 47 48#include <security/audit/audit.h> 49#include <security/mac/mac_framework.h> 50 51/* 52 * Syscall to push extended attribute configuration information into the VFS. 53 * Accepts a path, which it converts to a mountpoint, as well as a command 54 * (int cmd), and attribute name and misc data. 55 * 56 * Currently this is used only by UFS1 extended attributes. 57 */ 58int 59extattrctl(td, uap) 60 struct thread *td; 61 struct extattrctl_args /* { 62 const char *path; 63 int cmd; 64 const char *filename; 65 int attrnamespace; 66 const char *attrname; 67 } */ *uap; 68{ 69 struct vnode *filename_vp; 70 struct nameidata nd; 71 struct mount *mp, *mp_writable; 72 char attrname[EXTATTR_MAXNAMELEN]; 73 int vfslocked, fnvfslocked, error; 74 75 AUDIT_ARG(cmd, uap->cmd); 76 AUDIT_ARG(value, uap->attrnamespace); 77 /* 78 * uap->attrname is not always defined. We check again later when we 79 * invoke the VFS call so as to pass in NULL there if needed. 80 */ 81 if (uap->attrname != NULL) { 82 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, 83 NULL); 84 if (error) 85 return (error); 86 } 87 AUDIT_ARG(text, attrname); 88 89 vfslocked = fnvfslocked = 0; 90 /* 91 * uap->filename is not always defined. If it is, grab a vnode lock, 92 * which VFS_EXTATTRCTL() will later release. 93 */ 94 filename_vp = NULL; 95 if (uap->filename != NULL) { 96 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF | 97 AUDITVNODE2, UIO_USERSPACE, uap->filename, td); 98 error = namei(&nd); 99 if (error) 100 return (error); 101 fnvfslocked = NDHASGIANT(&nd); 102 filename_vp = nd.ni_vp; 103 NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK); 104 } 105 106 /* uap->path is always defined. */ 107 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 108 uap->path, td); 109 error = namei(&nd); 110 if (error) { 111 if (filename_vp != NULL) 112 vput(filename_vp); 113 goto out; 114 } 115 vfslocked = NDHASGIANT(&nd); 116 mp = nd.ni_vp->v_mount; 117 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH); 118 NDFREE(&nd, 0); 119 if (error) { 120 if (filename_vp != NULL) 121 vput(filename_vp); 122 goto out; 123 } 124 125 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace, 126 uap->attrname != NULL ? attrname : NULL, td); 127 128 vn_finished_write(mp_writable); 129 /* 130 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp, 131 * so vrele it if it is defined. 132 */ 133 if (filename_vp != NULL) 134 vrele(filename_vp); 135out: 136 VFS_UNLOCK_GIANT(fnvfslocked); 137 VFS_UNLOCK_GIANT(vfslocked); 138 return (error); 139} 140 141/*- 142 * Set a named extended attribute on a file or directory 143 * 144 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 145 * kernelspace string pointer "attrname", userspace buffer 146 * pointer "data", buffer length "nbytes", thread "td". 147 * Returns: 0 on success, an error number otherwise 148 * Locks: none 149 * References: vp must be a valid reference for the duration of the call 150 */ 151static int 152extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 153 void *data, size_t nbytes, struct thread *td) 154{ 155 struct mount *mp; 156 struct uio auio; 157 struct iovec aiov; 158 ssize_t cnt; 159 int error; 160 161 VFS_ASSERT_GIANT(vp->v_mount); 162 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 163 if (error) 164 return (error); 165 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 166 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 167 168 aiov.iov_base = data; 169 aiov.iov_len = nbytes; 170 auio.uio_iov = &aiov; 171 auio.uio_iovcnt = 1; 172 auio.uio_offset = 0; 173 if (nbytes > INT_MAX) { 174 error = EINVAL; 175 goto done; 176 } 177 auio.uio_resid = nbytes; 178 auio.uio_rw = UIO_WRITE; 179 auio.uio_segflg = UIO_USERSPACE; 180 auio.uio_td = td; 181 cnt = nbytes; 182 183#ifdef MAC 184 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace, 185 attrname, &auio); 186 if (error) 187 goto done; 188#endif 189 190 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, 191 td->td_ucred, td); 192 cnt -= auio.uio_resid; 193 td->td_retval[0] = cnt; 194 195done: 196 VOP_UNLOCK(vp, 0); 197 vn_finished_write(mp); 198 return (error); 199} 200 201int 202extattr_set_fd(td, uap) 203 struct thread *td; 204 struct extattr_set_fd_args /* { 205 int fd; 206 int attrnamespace; 207 const char *attrname; 208 void *data; 209 size_t nbytes; 210 } */ *uap; 211{ 212 struct file *fp; 213 char attrname[EXTATTR_MAXNAMELEN]; 214 int vfslocked, error; 215 216 AUDIT_ARG(fd, uap->fd); 217 AUDIT_ARG(value, uap->attrnamespace); 218 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 219 if (error) 220 return (error); 221 AUDIT_ARG(text, attrname); 222 223 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 224 if (error) 225 return (error); 226 227 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 228 error = extattr_set_vp(fp->f_vnode, uap->attrnamespace, 229 attrname, uap->data, uap->nbytes, td); 230 fdrop(fp, td); 231 VFS_UNLOCK_GIANT(vfslocked); 232 233 return (error); 234} 235 236int 237extattr_set_file(td, uap) 238 struct thread *td; 239 struct extattr_set_file_args /* { 240 const char *path; 241 int attrnamespace; 242 const char *attrname; 243 void *data; 244 size_t nbytes; 245 } */ *uap; 246{ 247 struct nameidata nd; 248 char attrname[EXTATTR_MAXNAMELEN]; 249 int vfslocked, error; 250 251 AUDIT_ARG(value, uap->attrnamespace); 252 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 253 if (error) 254 return (error); 255 AUDIT_ARG(text, attrname); 256 257 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 258 uap->path, td); 259 error = namei(&nd); 260 if (error) 261 return (error); 262 NDFREE(&nd, NDF_ONLY_PNBUF); 263 264 vfslocked = NDHASGIANT(&nd); 265 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, 266 uap->data, uap->nbytes, td); 267 268 vrele(nd.ni_vp); 269 VFS_UNLOCK_GIANT(vfslocked); 270 return (error); 271} 272 273int 274extattr_set_link(td, uap) 275 struct thread *td; 276 struct extattr_set_link_args /* { 277 const char *path; 278 int attrnamespace; 279 const char *attrname; 280 void *data; 281 size_t nbytes; 282 } */ *uap; 283{ 284 struct nameidata nd; 285 char attrname[EXTATTR_MAXNAMELEN]; 286 int vfslocked, error; 287 288 AUDIT_ARG(value, uap->attrnamespace); 289 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 290 if (error) 291 return (error); 292 AUDIT_ARG(text, attrname); 293 294 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 295 uap->path, td); 296 error = namei(&nd); 297 if (error) 298 return (error); 299 NDFREE(&nd, NDF_ONLY_PNBUF); 300 301 vfslocked = NDHASGIANT(&nd); 302 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, 303 uap->data, uap->nbytes, td); 304 305 vrele(nd.ni_vp); 306 VFS_UNLOCK_GIANT(vfslocked); 307 return (error); 308} 309 310/*- 311 * Get a named extended attribute on a file or directory 312 * 313 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 314 * kernelspace string pointer "attrname", userspace buffer 315 * pointer "data", buffer length "nbytes", thread "td". 316 * Returns: 0 on success, an error number otherwise 317 * Locks: none 318 * References: vp must be a valid reference for the duration of the call 319 */ 320static int 321extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 322 void *data, size_t nbytes, struct thread *td) 323{ 324 struct uio auio, *auiop; 325 struct iovec aiov; 326 ssize_t cnt; 327 size_t size, *sizep; 328 int error; 329 330 VFS_ASSERT_GIANT(vp->v_mount); 331 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ); 332 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 333 334 /* 335 * Slightly unusual semantics: if the user provides a NULL data 336 * pointer, they don't want to receive the data, just the maximum 337 * read length. 338 */ 339 auiop = NULL; 340 sizep = NULL; 341 cnt = 0; 342 if (data != NULL) { 343 aiov.iov_base = data; 344 aiov.iov_len = nbytes; 345 auio.uio_iov = &aiov; 346 auio.uio_iovcnt = 1; 347 auio.uio_offset = 0; 348 if (nbytes > INT_MAX) { 349 error = EINVAL; 350 goto done; 351 } 352 auio.uio_resid = nbytes; 353 auio.uio_rw = UIO_READ; 354 auio.uio_segflg = UIO_USERSPACE; 355 auio.uio_td = td; 356 auiop = &auio; 357 cnt = nbytes; 358 } else 359 sizep = &size; 360 361#ifdef MAC 362 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace, 363 attrname, &auio); 364 if (error) 365 goto done; 366#endif 367 368 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, 369 td->td_ucred, td); 370 371 if (auiop != NULL) { 372 cnt -= auio.uio_resid; 373 td->td_retval[0] = cnt; 374 } else 375 td->td_retval[0] = size; 376 377done: 378 VOP_UNLOCK(vp, 0); 379 return (error); 380} 381 382int 383extattr_get_fd(td, uap) 384 struct thread *td; 385 struct extattr_get_fd_args /* { 386 int fd; 387 int attrnamespace; 388 const char *attrname; 389 void *data; 390 size_t nbytes; 391 } */ *uap; 392{ 393 struct file *fp; 394 char attrname[EXTATTR_MAXNAMELEN]; 395 int vfslocked, error; 396 397 AUDIT_ARG(fd, uap->fd); 398 AUDIT_ARG(value, uap->attrnamespace); 399 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 400 if (error) 401 return (error); 402 AUDIT_ARG(text, attrname); 403 404 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 405 if (error) 406 return (error); 407 408 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 409 error = extattr_get_vp(fp->f_vnode, uap->attrnamespace, 410 attrname, uap->data, uap->nbytes, td); 411 412 fdrop(fp, td); 413 VFS_UNLOCK_GIANT(vfslocked); 414 return (error); 415} 416 417int 418extattr_get_file(td, uap) 419 struct thread *td; 420 struct extattr_get_file_args /* { 421 const char *path; 422 int attrnamespace; 423 const char *attrname; 424 void *data; 425 size_t nbytes; 426 } */ *uap; 427{ 428 struct nameidata nd; 429 char attrname[EXTATTR_MAXNAMELEN]; 430 int vfslocked, error; 431 432 AUDIT_ARG(value, uap->attrnamespace); 433 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 434 if (error) 435 return (error); 436 AUDIT_ARG(text, attrname); 437 438 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 439 uap->path, td); 440 error = namei(&nd); 441 if (error) 442 return (error); 443 NDFREE(&nd, NDF_ONLY_PNBUF); 444 445 vfslocked = NDHASGIANT(&nd); 446 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, 447 uap->data, uap->nbytes, td); 448 449 vrele(nd.ni_vp); 450 VFS_UNLOCK_GIANT(vfslocked); 451 return (error); 452} 453 454int 455extattr_get_link(td, uap) 456 struct thread *td; 457 struct extattr_get_link_args /* { 458 const char *path; 459 int attrnamespace; 460 const char *attrname; 461 void *data; 462 size_t nbytes; 463 } */ *uap; 464{ 465 struct nameidata nd; 466 char attrname[EXTATTR_MAXNAMELEN]; 467 int vfslocked, error; 468 469 AUDIT_ARG(value, uap->attrnamespace); 470 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 471 if (error) 472 return (error); 473 AUDIT_ARG(text, attrname); 474 475 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 476 uap->path, td); 477 error = namei(&nd); 478 if (error) 479 return (error); 480 NDFREE(&nd, NDF_ONLY_PNBUF); 481 482 vfslocked = NDHASGIANT(&nd); 483 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, 484 uap->data, uap->nbytes, td); 485 486 vrele(nd.ni_vp); 487 VFS_UNLOCK_GIANT(vfslocked); 488 return (error); 489} 490 491/* 492 * extattr_delete_vp(): Delete a named extended attribute on a file or 493 * directory 494 * 495 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 496 * kernelspace string pointer "attrname", proc "p" 497 * Returns: 0 on success, an error number otherwise 498 * Locks: none 499 * References: vp must be a valid reference for the duration of the call 500 */ 501static int 502extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 503 struct thread *td) 504{ 505 struct mount *mp; 506 int error; 507 508 VFS_ASSERT_GIANT(vp->v_mount); 509 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 510 if (error) 511 return (error); 512 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 513 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 514 515#ifdef MAC 516 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace, 517 attrname); 518 if (error) 519 goto done; 520#endif 521 522 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred, 523 td); 524 if (error == EOPNOTSUPP) 525 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 526 td->td_ucred, td); 527#ifdef MAC 528done: 529#endif 530 VOP_UNLOCK(vp, 0); 531 vn_finished_write(mp); 532 return (error); 533} 534 535int 536extattr_delete_fd(td, uap) 537 struct thread *td; 538 struct extattr_delete_fd_args /* { 539 int fd; 540 int attrnamespace; 541 const char *attrname; 542 } */ *uap; 543{ 544 struct file *fp; 545 char attrname[EXTATTR_MAXNAMELEN]; 546 int vfslocked, error; 547 548 AUDIT_ARG(fd, uap->fd); 549 AUDIT_ARG(value, uap->attrnamespace); 550 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 551 if (error) 552 return (error); 553 AUDIT_ARG(text, attrname); 554 555 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 556 if (error) 557 return (error); 558 559 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 560 error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace, 561 attrname, td); 562 fdrop(fp, td); 563 VFS_UNLOCK_GIANT(vfslocked); 564 return (error); 565} 566 567int 568extattr_delete_file(td, uap) 569 struct thread *td; 570 struct extattr_delete_file_args /* { 571 const char *path; 572 int attrnamespace; 573 const char *attrname; 574 } */ *uap; 575{ 576 struct nameidata nd; 577 char attrname[EXTATTR_MAXNAMELEN]; 578 int vfslocked, error; 579 580 AUDIT_ARG(value, uap->attrnamespace); 581 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 582 if (error) 583 return(error); 584 AUDIT_ARG(text, attrname); 585 586 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 587 uap->path, td); 588 error = namei(&nd); 589 if (error) 590 return(error); 591 NDFREE(&nd, NDF_ONLY_PNBUF); 592 593 vfslocked = NDHASGIANT(&nd); 594 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td); 595 vrele(nd.ni_vp); 596 VFS_UNLOCK_GIANT(vfslocked); 597 return(error); 598} 599 600int 601extattr_delete_link(td, uap) 602 struct thread *td; 603 struct extattr_delete_link_args /* { 604 const char *path; 605 int attrnamespace; 606 const char *attrname; 607 } */ *uap; 608{ 609 struct nameidata nd; 610 char attrname[EXTATTR_MAXNAMELEN]; 611 int vfslocked, error; 612 613 AUDIT_ARG(value, uap->attrnamespace); 614 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 615 if (error) 616 return(error); 617 AUDIT_ARG(text, attrname); 618 619 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 620 uap->path, td); 621 error = namei(&nd); 622 if (error) 623 return(error); 624 NDFREE(&nd, NDF_ONLY_PNBUF); 625 626 vfslocked = NDHASGIANT(&nd); 627 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td); 628 vrele(nd.ni_vp); 629 VFS_UNLOCK_GIANT(vfslocked); 630 return(error); 631} 632 633/*- 634 * Retrieve a list of extended attributes on a file or directory. 635 * 636 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace", 637 * userspace buffer pointer "data", buffer length "nbytes", 638 * thread "td". 639 * Returns: 0 on success, an error number otherwise 640 * Locks: none 641 * References: vp must be a valid reference for the duration of the call 642 */ 643static int 644extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, 645 size_t nbytes, struct thread *td) 646{ 647 struct uio auio, *auiop; 648 size_t size, *sizep; 649 struct iovec aiov; 650 ssize_t cnt; 651 int error; 652 653 VFS_ASSERT_GIANT(vp->v_mount); 654 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ); 655 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 656 657 auiop = NULL; 658 sizep = NULL; 659 cnt = 0; 660 if (data != NULL) { 661 aiov.iov_base = data; 662 aiov.iov_len = nbytes; 663 auio.uio_iov = &aiov; 664 auio.uio_iovcnt = 1; 665 auio.uio_offset = 0; 666 if (nbytes > INT_MAX) { 667 error = EINVAL; 668 goto done; 669 } 670 auio.uio_resid = nbytes; 671 auio.uio_rw = UIO_READ; 672 auio.uio_segflg = UIO_USERSPACE; 673 auio.uio_td = td; 674 auiop = &auio; 675 cnt = nbytes; 676 } else 677 sizep = &size; 678 679#ifdef MAC 680 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace); 681 if (error) 682 goto done; 683#endif 684 685 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, 686 td->td_ucred, td); 687 688 if (auiop != NULL) { 689 cnt -= auio.uio_resid; 690 td->td_retval[0] = cnt; 691 } else 692 td->td_retval[0] = size; 693 694done: 695 VOP_UNLOCK(vp, 0); 696 return (error); 697} 698 699 700int 701extattr_list_fd(td, uap) 702 struct thread *td; 703 struct extattr_list_fd_args /* { 704 int fd; 705 int attrnamespace; 706 void *data; 707 size_t nbytes; 708 } */ *uap; 709{ 710 struct file *fp; 711 int vfslocked, error; 712 713 AUDIT_ARG(fd, uap->fd); 714 AUDIT_ARG(value, uap->attrnamespace); 715 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 716 if (error) 717 return (error); 718 719 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 720 error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data, 721 uap->nbytes, td); 722 723 fdrop(fp, td); 724 VFS_UNLOCK_GIANT(vfslocked); 725 return (error); 726} 727 728int 729extattr_list_file(td, uap) 730 struct thread*td; 731 struct extattr_list_file_args /* { 732 const char *path; 733 int attrnamespace; 734 void *data; 735 size_t nbytes; 736 } */ *uap; 737{ 738 struct nameidata nd; 739 int vfslocked, error; 740 741 AUDIT_ARG(value, uap->attrnamespace); 742 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 743 uap->path, td); 744 error = namei(&nd); 745 if (error) 746 return (error); 747 NDFREE(&nd, NDF_ONLY_PNBUF); 748 749 vfslocked = NDHASGIANT(&nd); 750 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, 751 uap->nbytes, td); 752 753 vrele(nd.ni_vp); 754 VFS_UNLOCK_GIANT(vfslocked); 755 return (error); 756} 757 758int 759extattr_list_link(td, uap) 760 struct thread*td; 761 struct extattr_list_link_args /* { 762 const char *path; 763 int attrnamespace; 764 void *data; 765 size_t nbytes; 766 } */ *uap; 767{ 768 struct nameidata nd; 769 int vfslocked, error; 770 771 AUDIT_ARG(value, uap->attrnamespace); 772 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 773 uap->path, td); 774 error = namei(&nd); 775 if (error) 776 return (error); 777 NDFREE(&nd, NDF_ONLY_PNBUF); 778 779 vfslocked = NDHASGIANT(&nd); 780 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, 781 uap->nbytes, td); 782 783 vrele(nd.ni_vp); 784 VFS_UNLOCK_GIANT(vfslocked); 785 return (error); 786}
|