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