The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/vfs_acl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1999-2006 Robert N. M. Watson
    3  * All rights reserved.
    4  *
    5  * This software was developed by Robert Watson for the TrustedBSD Project.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 /*
   29  * Developed by the TrustedBSD Project.
   30  *
   31  * ACL system calls and other functions common across different ACL types.
   32  * Type-specific routines go into subr_acl_<type>.c.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/10.2/sys/kern/vfs_acl.c 280258 2015-03-19 13:37:36Z rwatson $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/sysproto.h>
   41 #include <sys/capsicum.h>
   42 #include <sys/fcntl.h>
   43 #include <sys/kernel.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mount.h>
   46 #include <sys/vnode.h>
   47 #include <sys/lock.h>
   48 #include <sys/mutex.h>
   49 #include <sys/namei.h>
   50 #include <sys/file.h>
   51 #include <sys/filedesc.h>
   52 #include <sys/proc.h>
   53 #include <sys/sysent.h>
   54 #include <sys/acl.h>
   55 
   56 #include <security/mac/mac_framework.h>
   57 
   58 CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
   59 
   60 MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
   61 
   62 static int      vacl_set_acl(struct thread *td, struct vnode *vp,
   63                     acl_type_t type, struct acl *aclp);
   64 static int      vacl_get_acl(struct thread *td, struct vnode *vp,
   65                     acl_type_t type, struct acl *aclp);
   66 static int      vacl_aclcheck(struct thread *td, struct vnode *vp,
   67                     acl_type_t type, struct acl *aclp);
   68 
   69 int
   70 acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
   71 {
   72         int i;
   73 
   74         if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
   75                 return (EINVAL);
   76         
   77         bzero(dest, sizeof(*dest));
   78 
   79         dest->acl_cnt = source->acl_cnt;
   80         dest->acl_maxcnt = ACL_MAX_ENTRIES;
   81 
   82         for (i = 0; i < dest->acl_cnt; i++) {
   83                 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
   84                 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
   85                 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
   86         }
   87 
   88         return (0);
   89 }
   90 
   91 int
   92 acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
   93 {
   94         int i;
   95 
   96         if (source->acl_cnt > OLDACL_MAX_ENTRIES)
   97                 return (EINVAL);
   98 
   99         bzero(dest, sizeof(*dest));
  100 
  101         dest->acl_cnt = source->acl_cnt;
  102 
  103         for (i = 0; i < dest->acl_cnt; i++) {
  104                 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
  105                 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
  106                 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
  107         }
  108 
  109         return (0);
  110 }
  111 
  112 /*
  113  * At one time, "struct ACL" was extended in order to add support for NFSv4
  114  * ACLs.  Instead of creating compatibility versions of all the ACL-related
  115  * syscalls, they were left intact.  It's possible to find out what the code
  116  * calling these syscalls (libc) expects basing on "type" argument - if it's
  117  * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
  118  * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
  119  * oldacl".  If it's something else, then it's the new "struct acl".  In the
  120  * latter case, the routines below just copyin/copyout the contents.  In the
  121  * former case, they copyin the "struct oldacl" and convert it to the new
  122  * format.
  123  */
  124 static int
  125 acl_copyin(void *user_acl, struct acl *kernel_acl, acl_type_t type)
  126 {
  127         int error;
  128         struct oldacl old;
  129 
  130         switch (type) {
  131         case ACL_TYPE_ACCESS_OLD:
  132         case ACL_TYPE_DEFAULT_OLD:
  133                 error = copyin(user_acl, &old, sizeof(old));
  134                 if (error != 0)
  135                         break;
  136                 acl_copy_oldacl_into_acl(&old, kernel_acl);
  137                 break;
  138 
  139         default:
  140                 error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
  141                 if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
  142                         return (EINVAL);
  143         }
  144 
  145         return (error);
  146 }
  147 
  148 static int
  149 acl_copyout(struct acl *kernel_acl, void *user_acl, acl_type_t type)
  150 {
  151         uint32_t am;
  152         int error;
  153         struct oldacl old;
  154 
  155         switch (type) {
  156         case ACL_TYPE_ACCESS_OLD:
  157         case ACL_TYPE_DEFAULT_OLD:
  158                 error = acl_copy_acl_into_oldacl(kernel_acl, &old);
  159                 if (error != 0)
  160                         break;
  161 
  162                 error = copyout(&old, user_acl, sizeof(old));
  163                 break;
  164 
  165         default:
  166                 error = fueword32((char *)user_acl +
  167                     offsetof(struct acl, acl_maxcnt), &am);
  168                 if (error == -1)
  169                         return (EFAULT);
  170                 if (am != ACL_MAX_ENTRIES)
  171                         return (EINVAL);
  172 
  173                 error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
  174         }
  175 
  176         return (error);
  177 }
  178 
  179 /*
  180  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
  181  * counterpart.  It's required for old (pre-NFSv4 ACLs) libc to work
  182  * with new kernel.  Fixing 'type' for old binaries with new libc
  183  * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
  184  */
  185 static int
  186 acl_type_unold(int type)
  187 {
  188         switch (type) {
  189         case ACL_TYPE_ACCESS_OLD:
  190                 return (ACL_TYPE_ACCESS);
  191 
  192         case ACL_TYPE_DEFAULT_OLD:
  193                 return (ACL_TYPE_DEFAULT);
  194 
  195         default:
  196                 return (type);
  197         }
  198 }
  199 
  200 /*
  201  * These calls wrap the real vnode operations, and are called by the syscall
  202  * code once the syscall has converted the path or file descriptor to a vnode
  203  * (unlocked).  The aclp pointer is assumed still to point to userland, so
  204  * this should not be consumed within the kernel except by syscall code.
  205  * Other code should directly invoke VOP_{SET,GET}ACL.
  206  */
  207 
  208 /*
  209  * Given a vnode, set its ACL.
  210  */
  211 static int
  212 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
  213     struct acl *aclp)
  214 {
  215         struct acl *inkernelacl;
  216         struct mount *mp;
  217         int error;
  218 
  219         inkernelacl = acl_alloc(M_WAITOK);
  220         error = acl_copyin(aclp, inkernelacl, type);
  221         if (error != 0)
  222                 goto out;
  223         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
  224         if (error != 0)
  225                 goto out;
  226         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  227 #ifdef MAC
  228         error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl);
  229         if (error != 0)
  230                 goto out_unlock;
  231 #endif
  232         error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
  233             td->td_ucred, td);
  234 #ifdef MAC
  235 out_unlock:
  236 #endif
  237         VOP_UNLOCK(vp, 0);
  238         vn_finished_write(mp);
  239 out:
  240         acl_free(inkernelacl);
  241         return (error);
  242 }
  243 
  244 /*
  245  * Given a vnode, get its ACL.
  246  */
  247 static int
  248 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
  249     struct acl *aclp)
  250 {
  251         struct acl *inkernelacl;
  252         int error;
  253 
  254         inkernelacl = acl_alloc(M_WAITOK | M_ZERO);
  255         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  256 #ifdef MAC
  257         error = mac_vnode_check_getacl(td->td_ucred, vp, type);
  258         if (error != 0)
  259                 goto out;
  260 #endif
  261         error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
  262             td->td_ucred, td);
  263 
  264 #ifdef MAC
  265 out:
  266 #endif
  267         VOP_UNLOCK(vp, 0);
  268         if (error == 0)
  269                 error = acl_copyout(inkernelacl, aclp, type);
  270         acl_free(inkernelacl);
  271         return (error);
  272 }
  273 
  274 /*
  275  * Given a vnode, delete its ACL.
  276  */
  277 static int
  278 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
  279 {
  280         struct mount *mp;
  281         int error;
  282 
  283         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
  284         if (error != 0)
  285                 return (error);
  286         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  287 #ifdef MAC
  288         error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
  289         if (error != 0)
  290                 goto out;
  291 #endif
  292         error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
  293 #ifdef MAC
  294 out:
  295 #endif
  296         VOP_UNLOCK(vp, 0);
  297         vn_finished_write(mp);
  298         return (error);
  299 }
  300 
  301 /*
  302  * Given a vnode, check whether an ACL is appropriate for it
  303  */
  304 static int
  305 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
  306     struct acl *aclp)
  307 {
  308         struct acl *inkernelacl;
  309         int error;
  310 
  311         inkernelacl = acl_alloc(M_WAITOK);
  312         error = acl_copyin(aclp, inkernelacl, type);
  313         if (error != 0)
  314                 goto out;
  315         error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl,
  316             td->td_ucred, td);
  317 out:
  318         acl_free(inkernelacl);
  319         return (error);
  320 }
  321 
  322 /*
  323  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
  324  * need to lock, as the vacl_ code will get/release any locks required.
  325  */
  326 
  327 /*
  328  * Given a file path, get an ACL for it
  329  */
  330 int
  331 sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
  332 {
  333         struct nameidata nd;
  334         int error;
  335 
  336         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
  337         error = namei(&nd);
  338         if (error == 0) {
  339                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  340                 NDFREE(&nd, 0);
  341         }
  342         return (error);
  343 }
  344 
  345 /*
  346  * Given a file path, get an ACL for it; don't follow links.
  347  */
  348 int
  349 sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
  350 {
  351         struct nameidata nd;
  352         int error;
  353 
  354         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
  355         error = namei(&nd);
  356         if (error == 0) {
  357                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  358                 NDFREE(&nd, 0);
  359         }
  360         return (error);
  361 }
  362 
  363 /*
  364  * Given a file path, set an ACL for it.
  365  */
  366 int
  367 sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
  368 {
  369         struct nameidata nd;
  370         int error;
  371 
  372         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
  373         error = namei(&nd);
  374         if (error == 0) {
  375                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  376                 NDFREE(&nd, 0);
  377         }
  378         return (error);
  379 }
  380 
  381 /*
  382  * Given a file path, set an ACL for it; don't follow links.
  383  */
  384 int
  385 sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
  386 {
  387         struct nameidata nd;
  388         int error;
  389 
  390         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
  391         error = namei(&nd);
  392         if (error == 0) {
  393                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  394                 NDFREE(&nd, 0);
  395         }
  396         return (error);
  397 }
  398 
  399 /*
  400  * Given a file descriptor, get an ACL for it.
  401  */
  402 int
  403 sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
  404 {
  405         struct file *fp;
  406         cap_rights_t rights;
  407         int error;
  408 
  409         error = getvnode(td->td_proc->p_fd, uap->filedes,
  410             cap_rights_init(&rights, CAP_ACL_GET), &fp);
  411         if (error == 0) {
  412                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
  413                 fdrop(fp, td);
  414         }
  415         return (error);
  416 }
  417 
  418 /*
  419  * Given a file descriptor, set an ACL for it.
  420  */
  421 int
  422 sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
  423 {
  424         struct file *fp;
  425         cap_rights_t rights;
  426         int error;
  427 
  428         error = getvnode(td->td_proc->p_fd, uap->filedes,
  429             cap_rights_init(&rights, CAP_ACL_SET), &fp);
  430         if (error == 0) {
  431                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
  432                 fdrop(fp, td);
  433         }
  434         return (error);
  435 }
  436 
  437 /*
  438  * Given a file path, delete an ACL from it.
  439  */
  440 int
  441 sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
  442 {
  443         struct nameidata nd;
  444         int error;
  445 
  446         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
  447         error = namei(&nd);
  448         if (error == 0) {
  449                 error = vacl_delete(td, nd.ni_vp, uap->type);
  450                 NDFREE(&nd, 0);
  451         }
  452         return (error);
  453 }
  454 
  455 /*
  456  * Given a file path, delete an ACL from it; don't follow links.
  457  */
  458 int
  459 sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
  460 {
  461         struct nameidata nd;
  462         int error;
  463 
  464         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
  465         error = namei(&nd);
  466         if (error == 0) {
  467                 error = vacl_delete(td, nd.ni_vp, uap->type);
  468                 NDFREE(&nd, 0);
  469         }
  470         return (error);
  471 }
  472 
  473 /*
  474  * Given a file path, delete an ACL from it.
  475  */
  476 int
  477 sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
  478 {
  479         struct file *fp;
  480         cap_rights_t rights;
  481         int error;
  482 
  483         error = getvnode(td->td_proc->p_fd, uap->filedes,
  484             cap_rights_init(&rights, CAP_ACL_DELETE), &fp);
  485         if (error == 0) {
  486                 error = vacl_delete(td, fp->f_vnode, uap->type);
  487                 fdrop(fp, td);
  488         }
  489         return (error);
  490 }
  491 
  492 /*
  493  * Given a file path, check an ACL for it.
  494  */
  495 int
  496 sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
  497 {
  498         struct nameidata nd;
  499         int error;
  500 
  501         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
  502         error = namei(&nd);
  503         if (error == 0) {
  504                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  505                 NDFREE(&nd, 0);
  506         }
  507         return (error);
  508 }
  509 
  510 /*
  511  * Given a file path, check an ACL for it; don't follow links.
  512  */
  513 int
  514 sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
  515 {
  516         struct nameidata nd;
  517         int error;
  518 
  519         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
  520         error = namei(&nd);
  521         if (error == 0) {
  522                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  523                 NDFREE(&nd, 0);
  524         }
  525         return (error);
  526 }
  527 
  528 /*
  529  * Given a file descriptor, check an ACL for it.
  530  */
  531 int
  532 sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
  533 {
  534         struct file *fp;
  535         cap_rights_t rights;
  536         int error;
  537 
  538         error = getvnode(td->td_proc->p_fd, uap->filedes,
  539             cap_rights_init(&rights, CAP_ACL_CHECK), &fp);
  540         if (error == 0) {
  541                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
  542                 fdrop(fp, td);
  543         }
  544         return (error);
  545 }
  546 
  547 struct acl *
  548 acl_alloc(int flags)
  549 {
  550         struct acl *aclp;
  551 
  552         aclp = malloc(sizeof(*aclp), M_ACL, flags);
  553         if (aclp == NULL)
  554                 return (NULL);
  555 
  556         aclp->acl_maxcnt = ACL_MAX_ENTRIES;
  557 
  558         return (aclp);
  559 }
  560 
  561 void
  562 acl_free(struct acl *aclp)
  563 {
  564 
  565         free(aclp, M_ACL);
  566 }

Cache object: f6ca7d0c342ddc7b9b201082efb17948


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.