1 /* $NetBSD: vfs_xattr.c,v 1.38 2022/10/25 23:22:36 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1989, 1993 34 * The Regents of the University of California. All rights reserved. 35 * (c) UNIX System Laboratories, Inc. 36 * All or some portions of this file are derived from material licensed 37 * to the University of California by American Telephone and Telegraph 38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 39 * the permission of UNIX System Laboratories, Inc. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 */ 65 66 /* 67 * VFS extended attribute support. 68 */ 69 70 #include <sys/cdefs.h> 71 __KERNEL_RCSID(0, "$NetBSD: vfs_xattr.c,v 1.38 2022/10/25 23:22:36 riastradh Exp $"); 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/namei.h> 76 #include <sys/filedesc.h> 77 #include <sys/kernel.h> 78 #include <sys/file.h> 79 #include <sys/vnode.h> 80 #include <sys/mount.h> 81 #include <sys/proc.h> 82 #include <sys/uio.h> 83 #include <sys/extattr.h> 84 #include <sys/xattr.h> 85 #include <sys/sysctl.h> 86 #include <sys/syscallargs.h> 87 #include <sys/kauth.h> 88 #include <sys/ktrace.h> 89 90 #include <miscfs/genfs/genfs.h> 91 92 static void 93 ktr_xattr_name(const char *str) 94 { 95 ktrkuser("xattr-name", (void *)__UNCONST(str), strlen(str)); 96 } 97 98 static void 99 ktr_xattr_val(const void *data, size_t cnt) 100 { 101 ktruser("xattr-val", __UNCONST(data), cnt, 0); 102 } 103 104 /* 105 * Credential check based on process requesting service, and per-attribute 106 * permissions. 107 * 108 * NOTE: Vnode must be locked. 109 */ 110 int 111 extattr_check_cred(struct vnode *vp, int attrspace, kauth_cred_t cred, 112 int access) 113 { 114 115 if (cred == NOCRED) 116 return 0; 117 118 return kauth_authorize_vnode(cred, kauth_extattr_action(access), vp, 119 NULL, genfs_can_extattr(vp, cred, access, attrspace)); 120 } 121 122 /* 123 * Default vfs_extattrctl routine for file systems that do not support 124 * it. 125 */ 126 /*ARGSUSED*/ 127 int 128 vfs_stdextattrctl(struct mount *mp, int cmt, struct vnode *vp, 129 int attrnamespace, const char *attrname) 130 { 131 132 if (vp != NULL) 133 VOP_UNLOCK(vp); 134 return EOPNOTSUPP; 135 } 136 137 /* 138 * Push extended attribute configuration information into the file 139 * system. 140 * 141 * NOTE: Not all file systems that support extended attributes will 142 * require the use of this system call. 143 */ 144 int 145 sys_extattrctl(struct lwp *l, const struct sys_extattrctl_args *uap, register_t *retval) 146 { 147 /* { 148 syscallarg(const char *) path; 149 syscallarg(int) cmd; 150 syscallarg(const char *) filename; 151 syscallarg(int) attrnamespace; 152 syscallarg(const char *) attrname; 153 } */ 154 struct vnode *path_vp, *file_vp; 155 struct pathbuf *file_pb; 156 struct nameidata file_nd; 157 char attrname[EXTATTR_MAXNAMELEN]; 158 int error; 159 160 if (SCARG(uap, attrname) != NULL) { 161 error = copyinstr(SCARG(uap, attrname), attrname, 162 sizeof(attrname), NULL); 163 if (error) 164 return error; 165 } 166 167 error = namei_simple_user(SCARG(uap, path), NSM_FOLLOW_NOEMULROOT, 168 &path_vp); 169 if (error) 170 return error; 171 172 file_vp = NULL; 173 if (SCARG(uap, filename) != NULL) { 174 error = pathbuf_copyin(SCARG(uap, filename), &file_pb); 175 if (error) { 176 vrele(path_vp); 177 return error; 178 } 179 NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, file_pb); 180 error = namei(&file_nd); 181 if (error) { 182 pathbuf_destroy(file_pb); 183 vrele(path_vp); 184 return error; 185 } 186 file_vp = file_nd.ni_vp; 187 pathbuf_destroy(file_pb); 188 } 189 190 error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp, 191 SCARG(uap, attrnamespace), 192 SCARG(uap, attrname) != NULL ? attrname : NULL); 193 194 if (file_vp != NULL) 195 vrele(file_vp); 196 vrele(path_vp); 197 198 return error; 199 } 200 201 /***************************************************************************** 202 * Internal routines to manipulate file system extended attributes: 203 * - set 204 * - get 205 * - delete 206 * - list 207 *****************************************************************************/ 208 209 /* 210 * extattr_set_vp: 211 * 212 * Set a named extended attribute on a file or directory. 213 */ 214 static int 215 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 216 const void *data, size_t nbytes, struct lwp *l, register_t *retval, 217 int flag) 218 { 219 struct uio auio; 220 struct iovec aiov; 221 ssize_t cnt; 222 int error; 223 224 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 225 226 if (flag) { 227 size_t attrlen; 228 229 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, 230 &attrlen, l->l_cred); 231 232 switch (error) { 233 case ENODATA: 234 if (flag & XATTR_REPLACE) 235 goto done; 236 break; 237 case 0: 238 if (flag & XATTR_CREATE) { 239 error = EEXIST; 240 goto done; 241 } 242 break; 243 default: 244 goto done; 245 break; 246 } 247 } 248 249 aiov.iov_base = __UNCONST(data); /* XXXUNCONST kills const */ 250 aiov.iov_len = nbytes; 251 auio.uio_iov = &aiov; 252 auio.uio_iovcnt = 1; 253 auio.uio_offset = 0; 254 if (nbytes > INT_MAX) { 255 error = EINVAL; 256 goto done; 257 } 258 auio.uio_resid = nbytes; 259 auio.uio_rw = UIO_WRITE; 260 KASSERT(l == curlwp); 261 auio.uio_vmspace = l->l_proc->p_vmspace; 262 cnt = nbytes; 263 264 ktr_xattr_name(attrname); 265 ktr_xattr_val(data, nbytes); 266 267 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, l->l_cred); 268 cnt -= auio.uio_resid; 269 retval[0] = cnt; 270 271 done: 272 VOP_UNLOCK(vp); 273 return error; 274 } 275 276 /* 277 * extattr_get_vp: 278 * 279 * Get a named extended attribute on a file or directory. 280 */ 281 static int 282 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 283 void *data, size_t nbytes, struct lwp *l, register_t *retval) 284 { 285 struct uio auio, *auiop; 286 struct iovec aiov; 287 ssize_t cnt; 288 size_t size, *sizep; 289 int error; 290 291 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 292 293 /* 294 * Slightly unusual semantics: if the user provides a NULL data 295 * pointer, they don't want to receive the data, just the maximum 296 * read length. 297 */ 298 auiop = NULL; 299 sizep = NULL; 300 cnt = 0; 301 if (data != NULL) { 302 aiov.iov_base = data; 303 aiov.iov_len = nbytes; 304 auio.uio_iov = &aiov; 305 auio.uio_iovcnt = 1; 306 auio.uio_offset = 0; 307 if (nbytes > INT_MAX) { 308 error = EINVAL; 309 goto done; 310 } 311 auio.uio_resid = nbytes; 312 auio.uio_rw = UIO_READ; 313 KASSERT(l == curlwp); 314 auio.uio_vmspace = l->l_proc->p_vmspace; 315 auiop = &auio; 316 cnt = nbytes; 317 } else 318 sizep = &size; 319 320 ktr_xattr_name(attrname); 321 322 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, 323 l->l_cred); 324 325 if (auiop != NULL) { 326 cnt -= auio.uio_resid; 327 retval[0] = cnt; 328 329 ktr_xattr_val(data, cnt); 330 } else 331 retval[0] = size; 332 333 done: 334 VOP_UNLOCK(vp); 335 return error; 336 } 337 338 /* 339 * extattr_delete_vp: 340 * 341 * Delete a named extended attribute on a file or directory. 342 */ 343 static int 344 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 345 struct lwp *l) 346 { 347 int error; 348 349 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 350 351 ktr_xattr_name(attrname); 352 353 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, l->l_cred); 354 if (error == EOPNOTSUPP) 355 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 356 l->l_cred); 357 358 VOP_UNLOCK(vp); 359 return error; 360 } 361 362 /* 363 * extattr_list_vp: 364 * 365 * Retrieve a list of extended attributes on a file or directory. 366 */ 367 static int 368 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes, 369 int flag, struct lwp *l, register_t *retval) 370 { 371 struct uio auio, *auiop; 372 size_t size, *sizep; 373 struct iovec aiov; 374 ssize_t cnt; 375 int error; 376 377 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 378 379 auiop = NULL; 380 sizep = NULL; 381 cnt = 0; 382 if (data != NULL) { 383 aiov.iov_base = data; 384 aiov.iov_len = nbytes; 385 auio.uio_iov = &aiov; 386 auio.uio_iovcnt = 1; 387 auio.uio_offset = 0; 388 if (nbytes > INT_MAX) { 389 error = EINVAL; 390 goto done; 391 } 392 auio.uio_resid = nbytes; 393 auio.uio_rw = UIO_READ; 394 KASSERT(l == curlwp); 395 auio.uio_vmspace = l->l_proc->p_vmspace; 396 auiop = &auio; 397 cnt = nbytes; 398 } else 399 sizep = &size; 400 401 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, flag, 402 l->l_cred); 403 404 if (auiop != NULL) { 405 cnt -= auio.uio_resid; 406 retval[0] = cnt; 407 408 ktruser("xattr-list", data, cnt, 0); 409 } else 410 retval[0] = size; 411 412 done: 413 VOP_UNLOCK(vp); 414 return error; 415 } 416 417 /***************************************************************************** 418 * BSD <sys/extattr.h> API for file system extended attributes 419 *****************************************************************************/ 420 421 int 422 sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, 423 register_t *retval) 424 { 425 /* { 426 syscallarg(int) fd; 427 syscallarg(int) attrnamespace; 428 syscallarg(const char *) attrname; 429 syscallarg(const void *) data; 430 syscallarg(size_t) nbytes; 431 } */ 432 struct file *fp; 433 struct vnode *vp; 434 char attrname[EXTATTR_MAXNAMELEN]; 435 int error; 436 437 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 438 NULL); 439 if (error) 440 return error; 441 442 error = fd_getvnode(SCARG(uap, fd), &fp); 443 if (error) 444 return error; 445 vp = fp->f_vnode; 446 447 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 448 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 449 450 fd_putfile(SCARG(uap, fd)); 451 return error; 452 } 453 454 int 455 sys_extattr_set_file(struct lwp *l, 456 const struct sys_extattr_set_file_args *uap, 457 register_t *retval) 458 { 459 /* { 460 syscallarg(const char *) path; 461 syscallarg(int) attrnamespace; 462 syscallarg(const char *) attrname; 463 syscallarg(const void *) data; 464 syscallarg(size_t) nbytes; 465 } */ 466 struct vnode *vp; 467 char attrname[EXTATTR_MAXNAMELEN]; 468 int error; 469 470 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 471 NULL); 472 if (error) 473 return error; 474 475 error = namei_simple_user(SCARG(uap, path), NSM_FOLLOW_NOEMULROOT, 476 &vp); 477 if (error) 478 return error; 479 480 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 481 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 482 483 vrele(vp); 484 return error; 485 } 486 487 int 488 sys_extattr_set_link(struct lwp *l, 489 const struct sys_extattr_set_link_args *uap, 490 register_t *retval) 491 { 492 /* { 493 syscallarg(const char *) path; 494 syscallarg(int) attrnamespace; 495 syscallarg(const char *) attrname; 496 syscallarg(const void *) data; 497 syscallarg(size_t) nbytes; 498 } */ 499 struct vnode *vp; 500 char attrname[EXTATTR_MAXNAMELEN]; 501 int error; 502 503 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 504 NULL); 505 if (error) 506 return error; 507 508 error = namei_simple_user(SCARG(uap, path), NSM_NOFOLLOW_NOEMULROOT, 509 &vp); 510 if (error) 511 return error; 512 513 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 514 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 515 516 vrele(vp); 517 return error; 518 } 519 520 int 521 sys_extattr_get_fd(struct lwp *l, 522 const struct sys_extattr_get_fd_args *uap, 523 register_t *retval) 524 { 525 /* { 526 syscallarg(int) fd; 527 syscallarg(int) attrnamespace; 528 syscallarg(const char *) attrname; 529 syscallarg(void *) data; 530 syscallarg(size_t) nbytes; 531 } */ 532 struct file *fp; 533 struct vnode *vp; 534 char attrname[EXTATTR_MAXNAMELEN]; 535 int error; 536 537 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 538 NULL); 539 if (error) 540 return error; 541 542 error = fd_getvnode(SCARG(uap, fd), &fp); 543 if (error) 544 return error; 545 vp = fp->f_vnode; 546 547 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 548 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 549 550 fd_putfile(SCARG(uap, fd)); 551 return error; 552 } 553 554 int 555 sys_extattr_get_file(struct lwp *l, 556 const struct sys_extattr_get_file_args *uap, 557 register_t *retval) 558 { 559 /* { 560 syscallarg(const char *) path; 561 syscallarg(int) attrnamespace; 562 syscallarg(const char *) attrname; 563 syscallarg(void *) data; 564 syscallarg(size_t) nbytes; 565 } */ 566 struct vnode *vp; 567 char attrname[EXTATTR_MAXNAMELEN]; 568 int error; 569 570 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 571 NULL); 572 if (error) 573 return error; 574 575 error = namei_simple_user(SCARG(uap, path), NSM_FOLLOW_NOEMULROOT, 576 &vp); 577 if (error) 578 return error; 579 580 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 581 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 582 583 vrele(vp); 584 return error; 585 } 586 587 int 588 sys_extattr_get_link(struct lwp *l, 589 const struct sys_extattr_get_link_args *uap, 590 register_t *retval) 591 { 592 /* { 593 syscallarg(const char *) path; 594 syscallarg(int) attrnamespace; 595 syscallarg(const char *) attrname; 596 syscallarg(void *) data; 597 syscallarg(size_t) nbytes; 598 } */ 599 struct vnode *vp; 600 char attrname[EXTATTR_MAXNAMELEN]; 601 int error; 602 603 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 604 NULL); 605 if (error) 606 return error; 607 608 error = namei_simple_user(SCARG(uap, path), NSM_NOFOLLOW_NOEMULROOT, 609 &vp); 610 if (error) 611 return error; 612 613 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 614 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 615 616 vrele(vp); 617 return error; 618 } 619 620 int 621 sys_extattr_delete_fd(struct lwp *l, 622 const struct sys_extattr_delete_fd_args *uap, 623 register_t *retval) 624 { 625 /* { 626 syscallarg(int) fd; 627 syscallarg(int) attrnamespace; 628 syscallarg(const char *) attrname; 629 } */ 630 struct file *fp; 631 struct vnode *vp; 632 char attrname[EXTATTR_MAXNAMELEN]; 633 int error; 634 635 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 636 NULL); 637 if (error) 638 return error; 639 640 error = fd_getvnode(SCARG(uap, fd), &fp); 641 if (error) 642 return error; 643 vp = fp->f_vnode; 644 645 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 646 647 fd_putfile(SCARG(uap, fd)); 648 return error; 649 } 650 651 int 652 sys_extattr_delete_file(struct lwp *l, 653 const struct sys_extattr_delete_file_args *uap, 654 register_t *retval) 655 { 656 /* { 657 syscallarg(const char *) path; 658 syscallarg(int) attrnamespace; 659 syscallarg(const char *) attrname; 660 } */ 661 struct vnode *vp; 662 char attrname[EXTATTR_MAXNAMELEN]; 663 int error; 664 665 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 666 NULL); 667 if (error) 668 return error; 669 670 error = namei_simple_user(SCARG(uap, path), NSM_FOLLOW_NOEMULROOT, 671 &vp); 672 if (error) 673 return error; 674 675 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 676 677 vrele(vp); 678 return error; 679 } 680 681 int 682 sys_extattr_delete_link(struct lwp *l, 683 const struct sys_extattr_delete_link_args *uap, 684 register_t *retval) 685 { 686 /* { 687 syscallarg(const char *) path; 688 syscallarg(int) attrnamespace; 689 syscallarg(const char *) attrname; 690 } */ 691 struct vnode *vp; 692 char attrname[EXTATTR_MAXNAMELEN]; 693 int error; 694 695 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 696 NULL); 697 if (error) 698 return error; 699 700 error = namei_simple_user(SCARG(uap, path), NSM_NOFOLLOW_NOEMULROOT, 701 &vp); 702 if (error) 703 return error; 704 705 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 706 707 vrele(vp); 708 return error; 709 } 710 711 int 712 sys_extattr_list_fd(struct lwp *l, 713 const struct sys_extattr_list_fd_args *uap, 714 register_t *retval) 715 { 716 /* { 717 syscallarg(int) fd; 718 syscallarg(int) attrnamespace; 719 syscallarg(void *) data; 720 syscallarg(size_t) nbytes; 721 } */ 722 struct file *fp; 723 struct vnode *vp; 724 int error; 725 726 error = fd_getvnode(SCARG(uap, fd), &fp); 727 if (error) 728 return error; 729 vp = fp->f_vnode; 730 731 error = extattr_list_vp(vp, SCARG(uap, attrnamespace), 732 SCARG(uap, data), SCARG(uap, nbytes), 733 EXTATTR_LIST_LENPREFIX, l, retval); 734 735 fd_putfile(SCARG(uap, fd)); 736 return error; 737 } 738 739 int 740 sys_extattr_list_file(struct lwp *l, 741 const struct sys_extattr_list_file_args *uap, 742 register_t *retval) 743 { 744 /* { 745 syscallarg(const char *) path; 746 syscallarg(int) attrnamespace; 747 syscallarg(void *) data; 748 syscallarg(size_t) nbytes; 749 } */ 750 struct vnode *vp; 751 int error; 752 753 error = namei_simple_user(SCARG(uap, path), NSM_FOLLOW_NOEMULROOT, 754 &vp); 755 if (error) 756 return error; 757 758 error = extattr_list_vp(vp, SCARG(uap, attrnamespace), 759 SCARG(uap, data), SCARG(uap, nbytes), 760 EXTATTR_LIST_LENPREFIX, l, retval); 761 762 vrele(vp); 763 return error; 764 } 765 766 int 767 sys_extattr_list_link(struct lwp *l, 768 const struct sys_extattr_list_link_args *uap, 769 register_t *retval) 770 { 771 /* { 772 syscallarg(const char *) path; 773 syscallarg(int) attrnamespace; 774 syscallarg(void *) data; 775 syscallarg(size_t) nbytes; 776 } */ 777 struct vnode *vp; 778 int error; 779 780 error = namei_simple_user(SCARG(uap, path), NSM_NOFOLLOW_NOEMULROOT, 781 &vp); 782 if (error) 783 return error; 784 785 error = extattr_list_vp(vp, SCARG(uap, attrnamespace), 786 SCARG(uap, data), SCARG(uap, nbytes), 787 EXTATTR_LIST_LENPREFIX, l, retval); 788 789 vrele(vp); 790 return error; 791 } 792 793 /***************************************************************************** 794 * Linux-compatible <sys/xattr.h> API for file system extended attributes 795 *****************************************************************************/ 796 797 #define MATCH_NS(ns, key) (strncmp(ns, key, sizeof(ns) - 1) == 0) 798 static int 799 xattr_native(const char *key) 800 { 801 802 if (MATCH_NS("system.", key)) 803 return EXTATTR_NAMESPACE_SYSTEM; 804 else if (MATCH_NS("user.", key)) 805 return EXTATTR_NAMESPACE_USER; 806 else if (MATCH_NS("security.", key)) 807 return EXTATTR_NAMESPACE_SYSTEM; 808 else if (MATCH_NS("trusted.", key)) 809 return EXTATTR_NAMESPACE_SYSTEM; 810 else 811 return EXTATTR_NAMESPACE_USER; 812 } 813 #undef MATCH_NS 814 815 #define XATTR_ERRNO(e) ((e) == EOPNOTSUPP ? ENOTSUP : (e)) 816 817 int 818 sys_setxattr(struct lwp *l, 819 const struct sys_setxattr_args *uap, 820 register_t *retval) 821 { 822 /* { 823 syscallarg(const char *) path; 824 syscallarg(const char *) name; 825 syscallarg(void *) value; 826 syscallarg(size_t) size; 827 syscallarg(int) flags; 828 } */ 829 struct vnode *vp; 830 char attrname[XATTR_NAME_MAX]; 831 int attrnamespace; 832 register_t attrlen; 833 int error; 834 835 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 836 NULL); 837 if (error) 838 goto out; 839 840 error = namei_simple_user(SCARG(uap, path), 841 NSM_FOLLOW_NOEMULROOT, &vp); 842 if (error) 843 goto out; 844 845 attrnamespace = xattr_native(attrname); 846 847 error = extattr_set_vp(vp, attrnamespace, 848 attrname, SCARG(uap, value), SCARG(uap, size), l, 849 &attrlen, SCARG(uap, flags)); 850 851 vrele(vp); 852 out: 853 *retval = (error == 0 ? 0 : -1); 854 return XATTR_ERRNO(error); 855 } 856 857 int 858 sys_lsetxattr(struct lwp *l, 859 const struct sys_lsetxattr_args *uap, 860 register_t *retval) 861 { 862 /* { 863 syscallarg(const char *) path; 864 syscallarg(const char *) name; 865 syscallarg(void *) value; 866 syscallarg(size_t) size; 867 syscallarg(int) flags; 868 } */ 869 struct vnode *vp; 870 char attrname[XATTR_NAME_MAX]; 871 int attrnamespace; 872 register_t attrlen; 873 int error; 874 875 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 876 NULL); 877 if (error) 878 goto out; 879 880 error = namei_simple_user(SCARG(uap, path), NSM_NOFOLLOW_NOEMULROOT, 881 &vp); 882 if (error) 883 goto out; 884 885 attrnamespace = xattr_native(attrname); 886 887 error = extattr_set_vp(vp, attrnamespace, 888 attrname, SCARG(uap, value), SCARG(uap, size), l, 889 &attrlen, SCARG(uap, flags)); 890 891 vrele(vp); 892 out: 893 *retval = (error == 0 ? 0 : -1); 894 return XATTR_ERRNO(error); 895 } 896 897 int 898 sys_fsetxattr(struct lwp *l, 899 const struct sys_fsetxattr_args *uap, 900 register_t *retval) 901 { 902 /* { 903 syscallarg(int) fd; 904 syscallarg(const char *) name; 905 syscallarg(void *) value; 906 syscallarg(size_t) size; 907 syscallarg(int) flags; 908 } */ 909 struct file *fp; 910 struct vnode *vp; 911 char attrname[XATTR_NAME_MAX]; 912 int attrnamespace; 913 register_t attrlen; 914 int error; 915 916 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 917 NULL); 918 if (error) 919 goto out; 920 921 error = fd_getvnode(SCARG(uap, fd), &fp); 922 if (error) 923 goto out; 924 vp = fp->f_vnode; 925 926 attrnamespace = xattr_native(attrname); 927 928 error = extattr_set_vp(vp, attrnamespace, 929 attrname, SCARG(uap, value), SCARG(uap, size), l, 930 &attrlen, SCARG(uap, flags)); 931 932 fd_putfile(SCARG(uap, fd)); 933 out: 934 *retval = (error == 0 ? 0 : -1); 935 return XATTR_ERRNO(error); 936 } 937 938 int 939 sys_getxattr(struct lwp *l, 940 const struct sys_getxattr_args *uap, 941 register_t *retval) 942 { 943 /* { 944 syscallarg(const char *) path; 945 syscallarg(const char *) name; 946 syscallarg(void *) value; 947 syscallarg(size_t) size; 948 } */ 949 struct vnode *vp; 950 char attrname[XATTR_NAME_MAX]; 951 int attrnamespace; 952 int error; 953 954 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 955 NULL); 956 if (error) 957 return error; 958 959 error = namei_simple_user(SCARG(uap, path), NSM_FOLLOW_NOEMULROOT, 960 &vp); 961 if (error) 962 return error; 963 964 attrnamespace = xattr_native(attrname); 965 966 error = extattr_get_vp(vp, attrnamespace, 967 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 968 969 vrele(vp); 970 return XATTR_ERRNO(error); 971 } 972 973 int 974 sys_lgetxattr(struct lwp *l, 975 const struct sys_lgetxattr_args *uap, 976 register_t *retval) 977 { 978 /* { 979 syscallarg(const char *) path; 980 syscallarg(const char *) name; 981 syscallarg(void *) value; 982 syscallarg(size_t) size; 983 } */ 984 struct vnode *vp; 985 char attrname[XATTR_NAME_MAX]; 986 int attrnamespace; 987 int error; 988 989 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 990 NULL); 991 if (error) 992 return error; 993 994 error = namei_simple_user(SCARG(uap, path), NSM_NOFOLLOW_NOEMULROOT, 995 &vp); 996 if (error) 997 return error; 998 999 attrnamespace = xattr_native(attrname); 1000 1001 error = extattr_get_vp(vp, attrnamespace, 1002 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 1003 1004 vrele(vp); 1005 return XATTR_ERRNO(error); 1006 } 1007 1008 int 1009 sys_fgetxattr(struct lwp *l, 1010 const struct sys_fgetxattr_args *uap, 1011 register_t *retval) 1012 { 1013 /* { 1014 syscallarg(int) fd; 1015 syscallarg(const char *) name; 1016 syscallarg(void *) value; 1017 syscallarg(size_t) size; 1018 } */ 1019 struct file *fp; 1020 struct vnode *vp; 1021 char attrname[XATTR_NAME_MAX]; 1022 int attrnamespace; 1023 int error; 1024 1025 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1026 NULL); 1027 if (error) 1028 return error; 1029 1030 error = fd_getvnode(SCARG(uap, fd), &fp); 1031 if (error) 1032 return error; 1033 vp = fp->f_vnode; 1034 1035 attrnamespace = xattr_native(attrname); 1036 1037 error = extattr_get_vp(vp, attrnamespace, 1038 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 1039 1040 fd_putfile(SCARG(uap, fd)); 1041 return XATTR_ERRNO(error); 1042 } 1043 1044 int 1045 sys_listxattr(struct lwp *l, 1046 const struct sys_listxattr_args *uap, 1047 register_t *retval) 1048 { 1049 /* { 1050 syscallarg(const char *) path; 1051 syscallarg(char *) list; 1052 syscallarg(size_t) size; 1053 } */ 1054 struct vnode *vp; 1055 char *list; 1056 size_t size; 1057 register_t listsize_usr, listsize_sys; 1058 int error; 1059 1060 error = namei_simple_user(SCARG(uap, path), NSM_FOLLOW_NOEMULROOT, 1061 &vp); 1062 if (error) 1063 return error; 1064 1065 list = SCARG(uap, list); 1066 size = SCARG(uap, size); 1067 1068 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1069 list, size, 0, l, &listsize_usr); 1070 if (error) 1071 goto out; 1072 1073 if (list) 1074 list += listsize_usr; 1075 if (size) 1076 size -= listsize_usr; 1077 1078 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1079 list, size, 0, l, &listsize_sys); 1080 switch (error) { 1081 case EPERM: 1082 error = 0; /* Ignore and just skip system EA */ 1083 listsize_sys = 0; 1084 break; 1085 case 0: 1086 break; 1087 default: 1088 goto out; 1089 break; 1090 } 1091 1092 *retval = listsize_usr + listsize_sys; 1093 out: 1094 vrele(vp); 1095 return XATTR_ERRNO(error); 1096 } 1097 1098 int 1099 sys_llistxattr(struct lwp *l, 1100 const struct sys_llistxattr_args *uap, 1101 register_t *retval) 1102 { 1103 /* { 1104 syscallarg(const char *) path; 1105 syscallarg(char *) list; 1106 syscallarg(size_t) size; 1107 } */ 1108 struct vnode *vp; 1109 char *list; 1110 size_t size; 1111 register_t listsize_usr, listsize_sys; 1112 int error; 1113 1114 error = namei_simple_user(SCARG(uap, path), NSM_NOFOLLOW_NOEMULROOT, 1115 &vp); 1116 if (error) 1117 return error; 1118 1119 list = SCARG(uap, list); 1120 size = SCARG(uap, size); 1121 1122 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1123 list, size, 0, l, &listsize_usr); 1124 if (error) 1125 goto out; 1126 if (list) 1127 list += listsize_usr; 1128 if (size) 1129 size -= listsize_usr; 1130 1131 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1132 list, size, 0, l, &listsize_sys); 1133 switch (error) { 1134 case EPERM: 1135 error = 0; /* Ignore and just skip system EA */ 1136 listsize_sys = 0; 1137 break; 1138 case 0: 1139 break; 1140 default: 1141 goto out; 1142 break; 1143 } 1144 1145 *retval = listsize_usr + listsize_sys; 1146 out: 1147 vrele(vp); 1148 return XATTR_ERRNO(error); 1149 } 1150 1151 int 1152 sys_flistxattr(struct lwp *l, 1153 const struct sys_flistxattr_args *uap, 1154 register_t *retval) 1155 { 1156 /* { 1157 syscallarg(int) fd; 1158 syscallarg(char *) list; 1159 syscallarg(size_t) size; 1160 } */ 1161 struct file *fp; 1162 struct vnode *vp; 1163 char *list; 1164 size_t size; 1165 register_t listsize_usr, listsize_sys; 1166 int error; 1167 1168 error = fd_getvnode(SCARG(uap, fd), &fp); 1169 if (error) 1170 return error; 1171 vp = fp->f_vnode; 1172 1173 list = SCARG(uap, list); 1174 size = SCARG(uap, size); 1175 1176 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1177 list, size, 0, l, &listsize_usr); 1178 if (error) 1179 goto out; 1180 1181 if (list) 1182 list += listsize_usr; 1183 if (size) 1184 size -= listsize_usr; 1185 1186 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1187 list, size, 0, l, &listsize_sys); 1188 switch (error) { 1189 case EPERM: 1190 error = 0; /* Ignore and just skip system EA */ 1191 listsize_sys = 0; 1192 break; 1193 case 0: 1194 break; 1195 default: 1196 goto out; 1197 break; 1198 } 1199 1200 *retval = listsize_usr + listsize_sys; 1201 out: 1202 fd_putfile(SCARG(uap, fd)); 1203 return XATTR_ERRNO(error); 1204 } 1205 1206 int 1207 sys_removexattr(struct lwp *l, 1208 const struct sys_removexattr_args *uap, 1209 register_t *retval) 1210 { 1211 /* { 1212 syscallarg(const char *) path; 1213 syscallarg(const char *) name; 1214 } */ 1215 struct vnode *vp; 1216 char attrname[XATTR_NAME_MAX]; 1217 int attrnamespace; 1218 int error; 1219 1220 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1221 NULL); 1222 if (error) 1223 return error; 1224 1225 error = namei_simple_user(SCARG(uap, path), NSM_FOLLOW_NOEMULROOT, 1226 &vp); 1227 if (error) 1228 return error; 1229 1230 attrnamespace = xattr_native(attrname); 1231 1232 error = extattr_delete_vp(vp, attrnamespace, attrname, l); 1233 1234 vrele(vp); 1235 return XATTR_ERRNO(error); 1236 } 1237 1238 int 1239 sys_lremovexattr(struct lwp *l, 1240 const struct sys_lremovexattr_args *uap, 1241 register_t *retval) 1242 { 1243 /* { 1244 syscallarg(const char *) path; 1245 syscallarg(const char *) name; 1246 } */ 1247 struct vnode *vp; 1248 char attrname[XATTR_NAME_MAX]; 1249 int attrnamespace; 1250 int error; 1251 1252 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1253 NULL); 1254 if (error) 1255 return error; 1256 1257 error = namei_simple_user(SCARG(uap, path), NSM_NOFOLLOW_NOEMULROOT, 1258 &vp); 1259 if (error) 1260 return error; 1261 1262 attrnamespace = xattr_native(attrname); 1263 1264 error = extattr_delete_vp(vp, attrnamespace, attrname, l); 1265 1266 vrele(vp); 1267 return XATTR_ERRNO(error); 1268 } 1269 1270 int 1271 sys_fremovexattr(struct lwp *l, 1272 const struct sys_fremovexattr_args *uap, 1273 register_t *retval) 1274 { 1275 /* { 1276 syscallarg(int) fd; 1277 syscallarg(const char *) name; 1278 } */ 1279 struct file *fp; 1280 struct vnode *vp; 1281 char attrname[XATTR_NAME_MAX]; 1282 int attrnamespace; 1283 int error; 1284 1285 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1286 NULL); 1287 if (error) 1288 return error; 1289 1290 error = fd_getvnode(SCARG(uap, fd), &fp); 1291 if (error) 1292 return error; 1293 vp = fp->f_vnode; 1294 1295 attrnamespace = xattr_native(attrname); 1296 1297 error = extattr_delete_vp(vp, attrnamespace, attrname, l); 1298 1299 fd_putfile(SCARG(uap, fd)); 1300 return XATTR_ERRNO(error); 1301 } 1302