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/acl.h>
   61 
   62 #include <security/audit/audit.h>
   63 #include <security/mac/mac_framework.h>
   64 
   65 CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
   66 
   67 MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
   68 
   69 static int      kern___acl_aclcheck_path(struct thread *td, const char *path,
   70                     acl_type_t type, struct acl *aclp, int follow);
   71 static int      kern___acl_delete_path(struct thread *td, const char *path,
   72                     acl_type_t type, int follow);
   73 static int      kern___acl_get_path(struct thread *td, const char *path,
   74                     acl_type_t type, struct acl *aclp, int follow);
   75 static int      kern___acl_set_path(struct thread *td, const char *path,
   76                     acl_type_t type, const struct acl *aclp, int follow);
   77 static int      vacl_set_acl(struct thread *td, struct vnode *vp,
   78                     acl_type_t type, const struct acl *aclp);
   79 static int      vacl_get_acl(struct thread *td, struct vnode *vp,
   80                     acl_type_t type, struct acl *aclp);
   81 static int      vacl_aclcheck(struct thread *td, struct vnode *vp,
   82                     acl_type_t type, const struct acl *aclp);
   83 
   84 int
   85 acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
   86 {
   87         int i;
   88 
   89         if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
   90                 return (EINVAL);
   91 
   92         bzero(dest, sizeof(*dest));
   93 
   94         dest->acl_cnt = source->acl_cnt;
   95         dest->acl_maxcnt = ACL_MAX_ENTRIES;
   96 
   97         for (i = 0; i < dest->acl_cnt; i++) {
   98                 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
   99                 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
  100                 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
  101         }
  102 
  103         return (0);
  104 }
  105 
  106 int
  107 acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
  108 {
  109         int i;
  110 
  111         if (source->acl_cnt > OLDACL_MAX_ENTRIES)
  112                 return (EINVAL);
  113 
  114         bzero(dest, sizeof(*dest));
  115 
  116         dest->acl_cnt = source->acl_cnt;
  117 
  118         for (i = 0; i < dest->acl_cnt; i++) {
  119                 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
  120                 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
  121                 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
  122         }
  123 
  124         return (0);
  125 }
  126 
  127 /*
  128  * At one time, "struct ACL" was extended in order to add support for NFSv4
  129  * ACLs.  Instead of creating compatibility versions of all the ACL-related
  130  * syscalls, they were left intact.  It's possible to find out what the code
  131  * calling these syscalls (libc) expects basing on "type" argument - if it's
  132  * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
  133  * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
  134  * oldacl".  If it's something else, then it's the new "struct acl".  In the
  135  * latter case, the routines below just copyin/copyout the contents.  In the
  136  * former case, they copyin the "struct oldacl" and convert it to the new
  137  * format.
  138  */
  139 static int
  140 acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type)
  141 {
  142         int error;
  143         struct oldacl old;
  144 
  145         switch (type) {
  146         case ACL_TYPE_ACCESS_OLD:
  147         case ACL_TYPE_DEFAULT_OLD:
  148                 error = copyin(user_acl, &old, sizeof(old));
  149                 if (error != 0)
  150                         break;
  151                 acl_copy_oldacl_into_acl(&old, kernel_acl);
  152                 break;
  153 
  154         default:
  155                 error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
  156                 if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
  157                         return (EINVAL);
  158         }
  159 
  160         return (error);
  161 }
  162 
  163 static int
  164 acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type)
  165 {
  166         uint32_t am;
  167         int error;
  168         struct oldacl old;
  169 
  170         switch (type) {
  171         case ACL_TYPE_ACCESS_OLD:
  172         case ACL_TYPE_DEFAULT_OLD:
  173                 error = acl_copy_acl_into_oldacl(kernel_acl, &old);
  174                 if (error != 0)
  175                         break;
  176 
  177                 error = copyout(&old, user_acl, sizeof(old));
  178                 break;
  179 
  180         default:
  181                 error = fueword32((char *)user_acl +
  182                     offsetof(struct acl, acl_maxcnt), &am);
  183                 if (error == -1)
  184                         return (EFAULT);
  185                 if (am != ACL_MAX_ENTRIES)
  186                         return (EINVAL);
  187 
  188                 error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
  189         }
  190 
  191         return (error);
  192 }
  193 
  194 /*
  195  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
  196  * counterpart.  It's required for old (pre-NFSv4 ACLs) libc to work
  197  * with new kernel.  Fixing 'type' for old binaries with new libc
  198  * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
  199  */
  200 static int
  201 acl_type_unold(int type)
  202 {
  203         switch (type) {
  204         case ACL_TYPE_ACCESS_OLD:
  205                 return (ACL_TYPE_ACCESS);
  206 
  207         case ACL_TYPE_DEFAULT_OLD:
  208                 return (ACL_TYPE_DEFAULT);
  209 
  210         default:
  211                 return (type);
  212         }
  213 }
  214 
  215 /*
  216  * These calls wrap the real vnode operations, and are called by the syscall
  217  * code once the syscall has converted the path or file descriptor to a vnode
  218  * (unlocked).  The aclp pointer is assumed still to point to userland, so
  219  * this should not be consumed within the kernel except by syscall code.
  220  * Other code should directly invoke VOP_{SET,GET}ACL.
  221  */
  222 
  223 /*
  224  * Given a vnode, set its ACL.
  225  */
  226 static int
  227 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
  228     const struct acl *aclp)
  229 {
  230         struct acl *inkernelacl;
  231         struct mount *mp;
  232         int error;
  233 
  234         AUDIT_ARG_VALUE(type);
  235         inkernelacl = acl_alloc(M_WAITOK);
  236         error = acl_copyin(aclp, inkernelacl, type);
  237         if (error != 0)
  238                 goto out;
  239         error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
  240         if (error != 0)
  241                 goto out;
  242         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  243         AUDIT_ARG_VNODE1(vp);
  244 #ifdef MAC
  245         error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl);
  246         if (error != 0)
  247                 goto out_unlock;
  248 #endif
  249         error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
  250             td->td_ucred, td);
  251 #ifdef MAC
  252 out_unlock:
  253 #endif
  254         VOP_UNLOCK(vp);
  255         vn_finished_write(mp);
  256 out:
  257         acl_free(inkernelacl);
  258         return (error);
  259 }
  260 
  261 /*
  262  * Given a vnode, get its ACL.
  263  */
  264 static int
  265 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
  266     struct acl *aclp)
  267 {
  268         struct acl *inkernelacl;
  269         int error;
  270 
  271         AUDIT_ARG_VALUE(type);
  272         inkernelacl = acl_alloc(M_WAITOK | M_ZERO);
  273         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  274         AUDIT_ARG_VNODE1(vp);
  275 #ifdef MAC
  276         error = mac_vnode_check_getacl(td->td_ucred, vp, type);
  277         if (error != 0)
  278                 goto out;
  279 #endif
  280         error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
  281             td->td_ucred, td);
  282 
  283 #ifdef MAC
  284 out:
  285 #endif
  286         VOP_UNLOCK(vp);
  287         if (error == 0)
  288                 error = acl_copyout(inkernelacl, aclp, type);
  289         acl_free(inkernelacl);
  290         return (error);
  291 }
  292 
  293 /*
  294  * Given a vnode, delete its ACL.
  295  */
  296 static int
  297 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
  298 {
  299         struct mount *mp;
  300         int error;
  301 
  302         AUDIT_ARG_VALUE(type);
  303         error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
  304         if (error != 0)
  305                 return (error);
  306         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  307         AUDIT_ARG_VNODE1(vp);
  308 #ifdef MAC
  309         error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
  310         if (error != 0)
  311                 goto out;
  312 #endif
  313         error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
  314 #ifdef MAC
  315 out:
  316 #endif
  317         VOP_UNLOCK(vp);
  318         vn_finished_write(mp);
  319         return (error);
  320 }
  321 
  322 /*
  323  * Given a vnode, check whether an ACL is appropriate for it
  324  *
  325  * XXXRW: No vnode lock held so can't audit vnode state...?
  326  */
  327 static int
  328 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
  329     const struct acl *aclp)
  330 {
  331         struct acl *inkernelacl;
  332         int error;
  333 
  334         inkernelacl = acl_alloc(M_WAITOK);
  335         error = acl_copyin(aclp, inkernelacl, type);
  336         if (error != 0)
  337                 goto out;
  338         error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl,
  339             td->td_ucred, td);
  340 out:
  341         acl_free(inkernelacl);
  342         return (error);
  343 }
  344 
  345 /*
  346  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
  347  * need to lock, as the vacl_ code will get/release any locks required.
  348  */
  349 
  350 /*
  351  * Given a file path, get an ACL for it
  352  */
  353 int
  354 sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
  355 {
  356 
  357         return (kern___acl_get_path(td, uap->path, uap->type, uap->aclp,
  358             FOLLOW));
  359 }
  360 
  361 /*
  362  * Given a file path, get an ACL for it; don't follow links.
  363  */
  364 int
  365 sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
  366 {
  367 
  368         return(kern___acl_get_path(td, uap->path, uap->type, uap->aclp,
  369             NOFOLLOW));
  370 }
  371 
  372 static int
  373 kern___acl_get_path(struct thread *td, const char *path, acl_type_t type,
  374     struct acl *aclp, int follow)
  375 {
  376         struct nameidata nd;
  377         int error;
  378 
  379         NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path);
  380         error = namei(&nd);
  381         if (error == 0) {
  382                 error = vacl_get_acl(td, nd.ni_vp, type, aclp);
  383                 vrele(nd.ni_vp);
  384                 NDFREE_PNBUF(&nd);
  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);
  419         error = namei(&nd);
  420         if (error == 0) {
  421                 error = vacl_set_acl(td, nd.ni_vp, type, aclp);
  422                 vrele(nd.ni_vp);
  423                 NDFREE_PNBUF(&nd);
  424         }
  425         return (error);
  426 }
  427 
  428 /*
  429  * Given a file descriptor, get an ACL for it.
  430  */
  431 int
  432 sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
  433 {
  434         struct file *fp;
  435         cap_rights_t rights;
  436         int error;
  437 
  438         AUDIT_ARG_FD(uap->filedes);
  439         error = getvnode(td, uap->filedes,
  440             cap_rights_init_one(&rights, CAP_ACL_GET), &fp);
  441         if (error == 0) {
  442                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
  443                 fdrop(fp, td);
  444         }
  445         return (error);
  446 }
  447 
  448 /*
  449  * Given a file descriptor, set an ACL for it.
  450  */
  451 int
  452 sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
  453 {
  454         struct file *fp;
  455         cap_rights_t rights;
  456         int error;
  457 
  458         AUDIT_ARG_FD(uap->filedes);
  459         error = getvnode(td, uap->filedes,
  460             cap_rights_init_one(&rights, CAP_ACL_SET), &fp);
  461         if (error == 0) {
  462                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
  463                 fdrop(fp, td);
  464         }
  465         return (error);
  466 }
  467 
  468 /*
  469  * Given a file path, delete an ACL from it.
  470  */
  471 int
  472 sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
  473 {
  474 
  475         return (kern___acl_delete_path(td, uap->path, uap->type, FOLLOW));
  476 }
  477 
  478 /*
  479  * Given a file path, delete an ACL from it; don't follow links.
  480  */
  481 int
  482 sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
  483 {
  484 
  485         return (kern___acl_delete_path(td, uap->path, uap->type, NOFOLLOW));
  486 }
  487 
  488 static int
  489 kern___acl_delete_path(struct thread *td, const char *path,
  490     acl_type_t type, int follow)
  491 {
  492         struct nameidata nd;
  493         int error;
  494 
  495         NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path);
  496         error = namei(&nd);
  497         if (error == 0) {
  498                 error = vacl_delete(td, nd.ni_vp, type);
  499                 vrele(nd.ni_vp);
  500                 NDFREE_PNBUF(&nd);
  501         }
  502         return (error);
  503 }
  504 
  505 /*
  506  * Given a file path, delete an ACL from it.
  507  */
  508 int
  509 sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
  510 {
  511         struct file *fp;
  512         cap_rights_t rights;
  513         int error;
  514 
  515         AUDIT_ARG_FD(uap->filedes);
  516         error = getvnode(td, uap->filedes,
  517             cap_rights_init_one(&rights, CAP_ACL_DELETE), &fp);
  518         if (error == 0) {
  519                 error = vacl_delete(td, fp->f_vnode, uap->type);
  520                 fdrop(fp, td);
  521         }
  522         return (error);
  523 }
  524 
  525 /*
  526  * Given a file path, check an ACL for it.
  527  */
  528 int
  529 sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
  530 {
  531 
  532         return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
  533             FOLLOW));
  534 }
  535 
  536 /*
  537  * Given a file path, check an ACL for it; don't follow links.
  538  */
  539 int
  540 sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
  541 {
  542         return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
  543             NOFOLLOW));
  544 }
  545 
  546 static int
  547 kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type,
  548     struct acl *aclp, int follow)
  549 {
  550         struct nameidata nd;
  551         int error;
  552 
  553         NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path);
  554         error = namei(&nd);
  555         if (error == 0) {
  556                 error = vacl_aclcheck(td, nd.ni_vp, type, aclp);
  557                 NDFREE_PNBUF(&nd);
  558         }
  559         return (error);
  560 }
  561 
  562 /*
  563  * Given a file descriptor, check an ACL for it.
  564  */
  565 int
  566 sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
  567 {
  568         struct file *fp;
  569         cap_rights_t rights;
  570         int error;
  571 
  572         AUDIT_ARG_FD(uap->filedes);
  573         error = getvnode(td, uap->filedes,
  574             cap_rights_init_one(&rights, CAP_ACL_CHECK), &fp);
  575         if (error == 0) {
  576                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
  577                 fdrop(fp, td);
  578         }
  579         return (error);
  580 }
  581 
  582 struct acl *
  583 acl_alloc(int flags)
  584 {
  585         struct acl *aclp;
  586 
  587         aclp = malloc(sizeof(*aclp), M_ACL, flags);
  588         if (aclp == NULL)
  589                 return (NULL);
  590 
  591         aclp->acl_maxcnt = ACL_MAX_ENTRIES;
  592 
  593         return (aclp);
  594 }
  595 
  596 void
  597 acl_free(struct acl *aclp)
  598 {
  599 
  600         free(aclp, M_ACL);
  601 }

Cache object: 290864bddb3ec77fbdb2d97e9a12cc59


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