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

Cache object: fd2170158885683aef94fd4fc33c3d89


[ 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.