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