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