1 /* $NetBSD: vfs_xattr.c,v 1.36 2021/06/27 09:13:08 christos 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.36 2021/06/27 09:13:08 christos 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), 168 NSM_FOLLOW_NOEMULROOT, &path_vp); 169 if (error) { 170 return (error); 171 } 172 173 file_vp = NULL; 174 if (SCARG(uap, filename) != NULL) { 175 error = pathbuf_copyin(SCARG(uap, filename), &file_pb); 176 if (error) { 177 vrele(path_vp); 178 return (error); 179 } 180 NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, file_pb); 181 error = namei(&file_nd); 182 if (error) { 183 pathbuf_destroy(file_pb); 184 vrele(path_vp); 185 return (error); 186 } 187 file_vp = file_nd.ni_vp; 188 pathbuf_destroy(file_pb); 189 } 190 191 error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp, 192 SCARG(uap, attrnamespace), 193 SCARG(uap, attrname) != NULL ? attrname : NULL); 194 195 if (file_vp != NULL) 196 vrele(file_vp); 197 vrele(path_vp); 198 199 return (error); 200 } 201 202 /***************************************************************************** 203 * Internal routines to manipulate file system extended attributes: 204 * - set 205 * - get 206 * - delete 207 * - list 208 *****************************************************************************/ 209 210 /* 211 * extattr_set_vp: 212 * 213 * Set a named extended attribute on a file or directory. 214 */ 215 static int 216 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 217 const void *data, size_t nbytes, struct lwp *l, register_t *retval, 218 int flag) 219 { 220 struct uio auio; 221 struct iovec aiov; 222 ssize_t cnt; 223 int error; 224 225 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 226 227 if (flag) { 228 size_t attrlen; 229 230 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, 231 &attrlen, l->l_cred); 232 233 switch (error) { 234 case ENODATA: 235 if (flag & XATTR_REPLACE) 236 goto done; 237 break; 238 case 0: 239 if (flag & XATTR_CREATE) { 240 error = EEXIST; 241 goto done; 242 } 243 break; 244 default: 245 goto done; 246 break; 247 } 248 } 249 250 aiov.iov_base = __UNCONST(data); /* XXXUNCONST kills const */ 251 aiov.iov_len = nbytes; 252 auio.uio_iov = &aiov; 253 auio.uio_iovcnt = 1; 254 auio.uio_offset = 0; 255 if (nbytes > INT_MAX) { 256 error = EINVAL; 257 goto done; 258 } 259 auio.uio_resid = nbytes; 260 auio.uio_rw = UIO_WRITE; 261 KASSERT(l == curlwp); 262 auio.uio_vmspace = l->l_proc->p_vmspace; 263 cnt = nbytes; 264 265 ktr_xattr_name(attrname); 266 ktr_xattr_val(data, nbytes); 267 268 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, l->l_cred); 269 cnt -= auio.uio_resid; 270 retval[0] = cnt; 271 272 done: 273 VOP_UNLOCK(vp); 274 return (error); 275 } 276 277 /* 278 * extattr_get_vp: 279 * 280 * Get a named extended attribute on a file or directory. 281 */ 282 static int 283 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 284 void *data, size_t nbytes, struct lwp *l, register_t *retval) 285 { 286 struct uio auio, *auiop; 287 struct iovec aiov; 288 ssize_t cnt; 289 size_t size, *sizep; 290 int error; 291 292 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 293 294 /* 295 * Slightly unusual semantics: if the user provides a NULL data 296 * pointer, they don't want to receive the data, just the maximum 297 * read length. 298 */ 299 auiop = NULL; 300 sizep = NULL; 301 cnt = 0; 302 if (data != NULL) { 303 aiov.iov_base = data; 304 aiov.iov_len = nbytes; 305 auio.uio_iov = &aiov; 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_offset = 0; 387 if (nbytes > INT_MAX) { 388 error = EINVAL; 389 goto done; 390 } 391 auio.uio_resid = nbytes; 392 auio.uio_rw = UIO_READ; 393 KASSERT(l == curlwp); 394 auio.uio_vmspace = l->l_proc->p_vmspace; 395 auiop = &auio; 396 cnt = nbytes; 397 } else 398 sizep = &size; 399 400 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, 401 flag, l->l_cred); 402 403 if (auiop != NULL) { 404 cnt -= auio.uio_resid; 405 retval[0] = cnt; 406 407 ktruser("xattr-list", data, cnt, 0); 408 } else 409 retval[0] = size; 410 411 done: 412 VOP_UNLOCK(vp); 413 return (error); 414 } 415 416 /***************************************************************************** 417 * BSD <sys/extattr.h> API for file system extended attributes 418 *****************************************************************************/ 419 420 int 421 sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, register_t *retval) 422 { 423 /* { 424 syscallarg(int) fd; 425 syscallarg(int) attrnamespace; 426 syscallarg(const char *) attrname; 427 syscallarg(const void *) data; 428 syscallarg(size_t) nbytes; 429 } */ 430 struct file *fp; 431 struct vnode *vp; 432 char attrname[EXTATTR_MAXNAMELEN]; 433 int error; 434 435 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 436 NULL); 437 if (error) 438 return (error); 439 440 error = fd_getvnode(SCARG(uap, fd), &fp); 441 if (error) 442 return (error); 443 vp = fp->f_vnode; 444 445 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 446 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 447 448 fd_putfile(SCARG(uap, fd)); 449 return (error); 450 } 451 452 int 453 sys_extattr_set_file(struct lwp *l, const struct sys_extattr_set_file_args *uap, register_t *retval) 454 { 455 /* { 456 syscallarg(const char *) path; 457 syscallarg(int) attrnamespace; 458 syscallarg(const char *) attrname; 459 syscallarg(const void *) data; 460 syscallarg(size_t) nbytes; 461 } */ 462 struct vnode *vp; 463 char attrname[EXTATTR_MAXNAMELEN]; 464 int error; 465 466 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 467 NULL); 468 if (error) 469 return (error); 470 471 error = namei_simple_user(SCARG(uap, path), 472 NSM_FOLLOW_NOEMULROOT, &vp); 473 if (error) 474 return (error); 475 476 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 477 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 478 479 vrele(vp); 480 return (error); 481 } 482 483 int 484 sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval) 485 { 486 /* { 487 syscallarg(const char *) path; 488 syscallarg(int) attrnamespace; 489 syscallarg(const char *) attrname; 490 syscallarg(const void *) data; 491 syscallarg(size_t) nbytes; 492 } */ 493 struct vnode *vp; 494 char attrname[EXTATTR_MAXNAMELEN]; 495 int error; 496 497 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 498 NULL); 499 if (error) 500 return (error); 501 502 error = namei_simple_user(SCARG(uap, path), 503 NSM_NOFOLLOW_NOEMULROOT, &vp); 504 if (error) 505 return (error); 506 507 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 508 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 509 510 vrele(vp); 511 return (error); 512 } 513 514 int 515 sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval) 516 { 517 /* { 518 syscallarg(int) fd; 519 syscallarg(int) attrnamespace; 520 syscallarg(const char *) attrname; 521 syscallarg(void *) data; 522 syscallarg(size_t) nbytes; 523 } */ 524 struct file *fp; 525 struct vnode *vp; 526 char attrname[EXTATTR_MAXNAMELEN]; 527 int error; 528 529 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 530 NULL); 531 if (error) 532 return (error); 533 534 error = fd_getvnode(SCARG(uap, fd), &fp); 535 if (error) 536 return (error); 537 vp = fp->f_vnode; 538 539 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 540 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 541 542 fd_putfile(SCARG(uap, fd)); 543 return (error); 544 } 545 546 int 547 sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval) 548 { 549 /* { 550 syscallarg(const char *) path; 551 syscallarg(int) attrnamespace; 552 syscallarg(const char *) attrname; 553 syscallarg(void *) data; 554 syscallarg(size_t) nbytes; 555 } */ 556 struct vnode *vp; 557 char attrname[EXTATTR_MAXNAMELEN]; 558 int error; 559 560 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 561 NULL); 562 if (error) 563 return (error); 564 565 error = namei_simple_user(SCARG(uap, path), 566 NSM_FOLLOW_NOEMULROOT, &vp); 567 if (error) 568 return (error); 569 570 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 571 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 572 573 vrele(vp); 574 return (error); 575 } 576 577 int 578 sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval) 579 { 580 /* { 581 syscallarg(const char *) path; 582 syscallarg(int) attrnamespace; 583 syscallarg(const char *) attrname; 584 syscallarg(void *) data; 585 syscallarg(size_t) nbytes; 586 } */ 587 struct vnode *vp; 588 char attrname[EXTATTR_MAXNAMELEN]; 589 int error; 590 591 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 592 NULL); 593 if (error) 594 return (error); 595 596 error = namei_simple_user(SCARG(uap, path), 597 NSM_NOFOLLOW_NOEMULROOT, &vp); 598 if (error) 599 return (error); 600 601 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 602 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 603 604 vrele(vp); 605 return (error); 606 } 607 608 int 609 sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval) 610 { 611 /* { 612 syscallarg(int) fd; 613 syscallarg(int) attrnamespace; 614 syscallarg(const char *) attrname; 615 } */ 616 struct file *fp; 617 struct vnode *vp; 618 char attrname[EXTATTR_MAXNAMELEN]; 619 int error; 620 621 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 622 NULL); 623 if (error) 624 return (error); 625 626 error = fd_getvnode(SCARG(uap, fd), &fp); 627 if (error) 628 return (error); 629 vp = fp->f_vnode; 630 631 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 632 633 fd_putfile(SCARG(uap, fd)); 634 return (error); 635 } 636 637 int 638 sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval) 639 { 640 /* { 641 syscallarg(const char *) path; 642 syscallarg(int) attrnamespace; 643 syscallarg(const char *) attrname; 644 } */ 645 struct vnode *vp; 646 char attrname[EXTATTR_MAXNAMELEN]; 647 int error; 648 649 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 650 NULL); 651 if (error) 652 return (error); 653 654 error = namei_simple_user(SCARG(uap, path), 655 NSM_FOLLOW_NOEMULROOT, &vp); 656 if (error) 657 return (error); 658 659 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 660 661 vrele(vp); 662 return (error); 663 } 664 665 int 666 sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval) 667 { 668 /* { 669 syscallarg(const char *) path; 670 syscallarg(int) attrnamespace; 671 syscallarg(const char *) attrname; 672 } */ 673 struct vnode *vp; 674 char attrname[EXTATTR_MAXNAMELEN]; 675 int error; 676 677 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 678 NULL); 679 if (error) 680 return (error); 681 682 error = namei_simple_user(SCARG(uap, path), 683 NSM_NOFOLLOW_NOEMULROOT, &vp); 684 if (error) 685 return (error); 686 687 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 688 689 vrele(vp); 690 return (error); 691 } 692 693 int 694 sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval) 695 { 696 /* { 697 syscallarg(int) fd; 698 syscallarg(int) attrnamespace; 699 syscallarg(void *) data; 700 syscallarg(size_t) nbytes; 701 } */ 702 struct file *fp; 703 struct vnode *vp; 704 int error; 705 706 error = fd_getvnode(SCARG(uap, fd), &fp); 707 if (error) 708 return (error); 709 vp = fp->f_vnode; 710 711 error = extattr_list_vp(vp, SCARG(uap, attrnamespace), 712 SCARG(uap, data), SCARG(uap, nbytes), 713 EXTATTR_LIST_LENPREFIX, l, retval); 714 715 fd_putfile(SCARG(uap, fd)); 716 return (error); 717 } 718 719 int 720 sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval) 721 { 722 /* { 723 syscallarg(const char *) path; 724 syscallarg(int) attrnamespace; 725 syscallarg(void *) data; 726 syscallarg(size_t) nbytes; 727 } */ 728 struct vnode *vp; 729 int error; 730 731 error = namei_simple_user(SCARG(uap, path), 732 NSM_FOLLOW_NOEMULROOT, &vp); 733 if (error) 734 return (error); 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 vrele(vp); 741 return (error); 742 } 743 744 int 745 sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval) 746 { 747 /* { 748 syscallarg(const char *) path; 749 syscallarg(int) attrnamespace; 750 syscallarg(void *) data; 751 syscallarg(size_t) nbytes; 752 } */ 753 struct vnode *vp; 754 int error; 755 756 error = namei_simple_user(SCARG(uap, path), 757 NSM_NOFOLLOW_NOEMULROOT, &vp); 758 if (error) 759 return (error); 760 761 error = extattr_list_vp(vp, SCARG(uap, attrnamespace), 762 SCARG(uap, data), SCARG(uap, nbytes), 763 EXTATTR_LIST_LENPREFIX, l, retval); 764 765 vrele(vp); 766 return (error); 767 } 768 769 /***************************************************************************** 770 * Linux-compatible <sys/xattr.h> API for file system extended attributes 771 *****************************************************************************/ 772 773 #define MATCH_NS(ns, key) (strncmp(ns, key, sizeof(ns) - 1) == 0) 774 static int 775 xattr_native(const char *key) { 776 if (MATCH_NS("system.", key)) 777 return EXTATTR_NAMESPACE_SYSTEM; 778 else if (MATCH_NS("user.", key)) 779 return EXTATTR_NAMESPACE_USER; 780 else if (MATCH_NS("security.", key)) 781 return EXTATTR_NAMESPACE_SYSTEM; 782 else if (MATCH_NS("trusted.", key)) 783 return EXTATTR_NAMESPACE_SYSTEM; 784 else 785 return EXTATTR_NAMESPACE_USER; 786 787 } 788 #undef MATCH_NS 789 790 #define XATTR_ERRNO(e) ((e) == EOPNOTSUPP ? ENOTSUP : (e)) 791 792 int 793 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval) 794 { 795 /* { 796 syscallarg(const char *) path; 797 syscallarg(const char *) name; 798 syscallarg(void *) value; 799 syscallarg(size_t) size; 800 syscallarg(int) flags; 801 } */ 802 struct vnode *vp; 803 char attrname[XATTR_NAME_MAX]; 804 int attrnamespace; 805 register_t attrlen; 806 int error; 807 808 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 809 NULL); 810 if (error) 811 goto out; 812 813 error = namei_simple_user(SCARG(uap, path), 814 NSM_FOLLOW_NOEMULROOT, &vp); 815 if (error) 816 goto out; 817 818 attrnamespace = xattr_native(attrname); 819 820 error = extattr_set_vp(vp, attrnamespace, 821 attrname, SCARG(uap, value), SCARG(uap, size), l, 822 &attrlen, SCARG(uap, flags)); 823 824 vrele(vp); 825 out: 826 *retval = (error == 0) ? 0 : -1; 827 return (XATTR_ERRNO(error)); 828 } 829 830 int 831 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval) 832 { 833 /* { 834 syscallarg(const char *) path; 835 syscallarg(const char *) name; 836 syscallarg(void *) value; 837 syscallarg(size_t) size; 838 syscallarg(int) flags; 839 } */ 840 struct vnode *vp; 841 char attrname[XATTR_NAME_MAX]; 842 int attrnamespace; 843 register_t attrlen; 844 int error; 845 846 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 847 NULL); 848 if (error) 849 goto out; 850 851 error = namei_simple_user(SCARG(uap, path), 852 NSM_NOFOLLOW_NOEMULROOT, &vp); 853 if (error) 854 goto out; 855 856 attrnamespace = xattr_native(attrname); 857 858 error = extattr_set_vp(vp, attrnamespace, 859 attrname, SCARG(uap, value), SCARG(uap, size), l, 860 &attrlen, SCARG(uap, flags)); 861 862 vrele(vp); 863 out: 864 *retval = (error == 0) ? 0 : -1; 865 return (XATTR_ERRNO(error)); 866 } 867 868 int 869 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval) 870 { 871 /* { 872 syscallarg(int) fd; 873 syscallarg(const char *) name; 874 syscallarg(void *) value; 875 syscallarg(size_t) size; 876 syscallarg(int) flags; 877 } */ 878 struct file *fp; 879 struct vnode *vp; 880 char attrname[XATTR_NAME_MAX]; 881 int attrnamespace; 882 register_t attrlen; 883 int error; 884 885 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 886 NULL); 887 if (error) 888 goto out; 889 890 error = fd_getvnode(SCARG(uap, fd), &fp); 891 if (error) 892 goto out; 893 vp = fp->f_vnode; 894 895 attrnamespace = xattr_native(attrname); 896 897 error = extattr_set_vp(vp, attrnamespace, 898 attrname, SCARG(uap, value), SCARG(uap, size), l, 899 &attrlen, SCARG(uap, flags)); 900 901 fd_putfile(SCARG(uap, fd)); 902 out: 903 *retval = (error == 0) ? 0 : -1; 904 return (XATTR_ERRNO(error)); 905 } 906 907 int 908 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval) 909 { 910 /* { 911 syscallarg(const char *) path; 912 syscallarg(const char *) name; 913 syscallarg(void *) value; 914 syscallarg(size_t) size; 915 } */ 916 struct vnode *vp; 917 char attrname[XATTR_NAME_MAX]; 918 int attrnamespace; 919 int error; 920 921 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 922 NULL); 923 if (error) 924 return (error); 925 926 error = namei_simple_user(SCARG(uap, path), 927 NSM_FOLLOW_NOEMULROOT, &vp); 928 if (error) 929 return (error); 930 931 attrnamespace = xattr_native(attrname); 932 933 error = extattr_get_vp(vp, attrnamespace, 934 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 935 936 vrele(vp); 937 return (XATTR_ERRNO(error)); 938 } 939 940 int 941 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, 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), 960 NSM_NOFOLLOW_NOEMULROOT, &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_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval) 975 { 976 /* { 977 syscallarg(int) fd; 978 syscallarg(const char *) name; 979 syscallarg(void *) value; 980 syscallarg(size_t) size; 981 } */ 982 struct file *fp; 983 struct vnode *vp; 984 char attrname[XATTR_NAME_MAX]; 985 int attrnamespace; 986 int error; 987 988 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 989 NULL); 990 if (error) 991 return (error); 992 993 error = fd_getvnode(SCARG(uap, fd), &fp); 994 if (error) 995 return (error); 996 vp = fp->f_vnode; 997 998 attrnamespace = xattr_native(attrname); 999 1000 error = extattr_get_vp(vp, attrnamespace, 1001 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 1002 1003 fd_putfile(SCARG(uap, fd)); 1004 return (XATTR_ERRNO(error)); 1005 } 1006 1007 int 1008 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval) 1009 { 1010 /* { 1011 syscallarg(const char *) path; 1012 syscallarg(char *) list; 1013 syscallarg(size_t) size; 1014 } */ 1015 struct vnode *vp; 1016 char *list; 1017 size_t size; 1018 register_t listsize_usr, listsize_sys; 1019 int error; 1020 1021 error = namei_simple_user(SCARG(uap, path), 1022 NSM_FOLLOW_NOEMULROOT, &vp); 1023 if (error) 1024 return (error); 1025 1026 list = SCARG(uap, list); 1027 size = SCARG(uap, size); 1028 1029 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1030 list, size, 0, l, &listsize_usr); 1031 if (error) 1032 goto out; 1033 1034 if (list) 1035 list += listsize_usr; 1036 if (size) 1037 size -= listsize_usr; 1038 1039 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1040 list, size, 0, l, &listsize_sys); 1041 switch (error) { 1042 case EPERM: 1043 error = 0; /* Ignore and just skip system EA */ 1044 listsize_sys = 0; 1045 break; 1046 case 0: 1047 break; 1048 default: 1049 goto out; 1050 break; 1051 } 1052 1053 *retval = listsize_usr + listsize_sys; 1054 1055 out: 1056 vrele(vp); 1057 return (XATTR_ERRNO(error)); 1058 } 1059 1060 int 1061 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval) 1062 { 1063 /* { 1064 syscallarg(const char *) path; 1065 syscallarg(char *) list; 1066 syscallarg(size_t) size; 1067 } */ 1068 struct vnode *vp; 1069 char *list; 1070 size_t size; 1071 register_t listsize_usr, listsize_sys; 1072 int error; 1073 1074 error = namei_simple_user(SCARG(uap, path), 1075 NSM_NOFOLLOW_NOEMULROOT, &vp); 1076 if (error) 1077 return (error); 1078 1079 list = SCARG(uap, list); 1080 size = SCARG(uap, size); 1081 1082 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1083 list, size, 0, l, &listsize_usr); 1084 if (error) 1085 goto out; 1086 if (list) 1087 list += listsize_usr; 1088 if (size) 1089 size -= listsize_usr; 1090 1091 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1092 list, size, 0, l, &listsize_sys); 1093 switch (error) { 1094 case EPERM: 1095 error = 0; /* Ignore and just skip system EA */ 1096 listsize_sys = 0; 1097 break; 1098 case 0: 1099 break; 1100 default: 1101 goto out; 1102 break; 1103 } 1104 1105 *retval = listsize_usr + listsize_sys; 1106 out: 1107 vrele(vp); 1108 return (XATTR_ERRNO(error)); 1109 } 1110 1111 int 1112 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval) 1113 { 1114 /* { 1115 syscallarg(int) fd; 1116 syscallarg(char *) list; 1117 syscallarg(size_t) size; 1118 } */ 1119 struct file *fp; 1120 struct vnode *vp; 1121 char *list; 1122 size_t size; 1123 register_t listsize_usr, listsize_sys; 1124 int error; 1125 1126 error = fd_getvnode(SCARG(uap, fd), &fp); 1127 if (error) 1128 return (error); 1129 vp = fp->f_vnode; 1130 1131 list = SCARG(uap, list); 1132 size = SCARG(uap, size); 1133 1134 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1135 list, size, 0, l, &listsize_usr); 1136 if (error) 1137 goto out; 1138 1139 if (list) 1140 list += listsize_usr; 1141 if (size) 1142 size -= listsize_usr; 1143 1144 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1145 list, size, 0, l, &listsize_sys); 1146 switch (error) { 1147 case EPERM: 1148 error = 0; /* Ignore and just skip system EA */ 1149 listsize_sys = 0; 1150 break; 1151 case 0: 1152 break; 1153 default: 1154 goto out; 1155 break; 1156 } 1157 1158 *retval = listsize_usr + listsize_sys; 1159 out: 1160 1161 fd_putfile(SCARG(uap, fd)); 1162 return (XATTR_ERRNO(error)); 1163 } 1164 1165 int 1166 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval) 1167 { 1168 /* { 1169 syscallarg(const char *) path; 1170 syscallarg(const char *) name; 1171 } */ 1172 struct vnode *vp; 1173 char attrname[XATTR_NAME_MAX]; 1174 int attrnamespace; 1175 int error; 1176 1177 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1178 NULL); 1179 if (error) 1180 return (error); 1181 1182 error = namei_simple_user(SCARG(uap, path), 1183 NSM_FOLLOW_NOEMULROOT, &vp); 1184 if (error) 1185 return (error); 1186 1187 attrnamespace = xattr_native(attrname); 1188 1189 error = extattr_delete_vp(vp, attrnamespace, attrname, l); 1190 1191 vrele(vp); 1192 return (XATTR_ERRNO(error)); 1193 } 1194 1195 int 1196 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval) 1197 { 1198 /* { 1199 syscallarg(const char *) path; 1200 syscallarg(const char *) name; 1201 } */ 1202 struct vnode *vp; 1203 char attrname[XATTR_NAME_MAX]; 1204 int attrnamespace; 1205 int error; 1206 1207 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1208 NULL); 1209 if (error) 1210 return (error); 1211 1212 error = namei_simple_user(SCARG(uap, path), 1213 NSM_NOFOLLOW_NOEMULROOT, &vp); 1214 if (error) 1215 return (error); 1216 1217 attrnamespace = xattr_native(attrname); 1218 1219 error = extattr_delete_vp(vp, attrnamespace, attrname, l); 1220 1221 vrele(vp); 1222 return (XATTR_ERRNO(error)); 1223 } 1224 1225 int 1226 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval) 1227 { 1228 /* { 1229 syscallarg(int) fd; 1230 syscallarg(const char *) name; 1231 } */ 1232 struct file *fp; 1233 struct vnode *vp; 1234 char attrname[XATTR_NAME_MAX]; 1235 int attrnamespace; 1236 int error; 1237 1238 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1239 NULL); 1240 if (error) 1241 return (error); 1242 1243 error = fd_getvnode(SCARG(uap, fd), &fp); 1244 if (error) 1245 return (error); 1246 vp = fp->f_vnode; 1247 1248 attrnamespace = xattr_native(attrname); 1249 1250 error = extattr_delete_vp(vp, attrnamespace, attrname, l); 1251 1252 fd_putfile(SCARG(uap, fd)); 1253 return (XATTR_ERRNO(error)); 1254 } 1255