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