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