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 | 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 | 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, td);
  380         error = namei(&nd);
  381         if (error == 0) {
  382                 error = vacl_get_acl(td, nd.ni_vp, type, aclp);
  383                 NDFREE(&nd, 0);
  384         }
  385         return (error);
  386 }
  387 
  388 /*
  389  * Given a file path, set an ACL for it.
  390  */
  391 int
  392 sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
  393 {
  394 
  395         return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp,
  396             FOLLOW));
  397 }
  398 
  399 /*
  400  * Given a file path, set an ACL for it; don't follow links.
  401  */
  402 int
  403 sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
  404 {
  405 
  406         return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp,
  407             NOFOLLOW));
  408 }
  409 
  410 static int
  411 kern___acl_set_path(struct thread *td, const char *path,
  412     acl_type_t type, const struct acl *aclp, int follow)
  413 {
  414         struct nameidata nd;
  415         int error;
  416 
  417         NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td);
  418         error = namei(&nd);
  419         if (error == 0) {
  420                 error = vacl_set_acl(td, nd.ni_vp, type, aclp);
  421                 NDFREE(&nd, 0);
  422         }
  423         return (error);
  424 }
  425 
  426 /*
  427  * Given a file descriptor, get an ACL for it.
  428  */
  429 int
  430 sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
  431 {
  432         struct file *fp;
  433         cap_rights_t rights;
  434         int error;
  435 
  436         AUDIT_ARG_FD(uap->filedes);
  437         error = getvnode(td, uap->filedes,
  438             cap_rights_init_one(&rights, CAP_ACL_GET), &fp);
  439         if (error == 0) {
  440                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
  441                 fdrop(fp, td);
  442         }
  443         return (error);
  444 }
  445 
  446 /*
  447  * Given a file descriptor, set an ACL for it.
  448  */
  449 int
  450 sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
  451 {
  452         struct file *fp;
  453         cap_rights_t rights;
  454         int error;
  455 
  456         AUDIT_ARG_FD(uap->filedes);
  457         error = getvnode(td, uap->filedes,
  458             cap_rights_init_one(&rights, CAP_ACL_SET), &fp);
  459         if (error == 0) {
  460                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
  461                 fdrop(fp, td);
  462         }
  463         return (error);
  464 }
  465 
  466 /*
  467  * Given a file path, delete an ACL from it.
  468  */
  469 int
  470 sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
  471 {
  472 
  473         return (kern___acl_delete_path(td, uap->path, uap->type, FOLLOW));
  474 }
  475 
  476 /*
  477  * Given a file path, delete an ACL from it; don't follow links.
  478  */
  479 int
  480 sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
  481 {
  482 
  483         return (kern___acl_delete_path(td, uap->path, uap->type, NOFOLLOW));
  484 }
  485 
  486 static int
  487 kern___acl_delete_path(struct thread *td, const char *path,
  488     acl_type_t type, int follow)
  489 {
  490         struct nameidata nd;
  491         int error;
  492 
  493         NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path, td);
  494         error = namei(&nd);
  495         if (error == 0) {
  496                 error = vacl_delete(td, nd.ni_vp, type);
  497                 NDFREE(&nd, 0);
  498         }
  499         return (error);
  500 }
  501 
  502 /*
  503  * Given a file path, delete an ACL from it.
  504  */
  505 int
  506 sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
  507 {
  508         struct file *fp;
  509         cap_rights_t rights;
  510         int error;
  511 
  512         AUDIT_ARG_FD(uap->filedes);
  513         error = getvnode(td, uap->filedes,
  514             cap_rights_init_one(&rights, CAP_ACL_DELETE), &fp);
  515         if (error == 0) {
  516                 error = vacl_delete(td, fp->f_vnode, uap->type);
  517                 fdrop(fp, td);
  518         }
  519         return (error);
  520 }
  521 
  522 /*
  523  * Given a file path, check an ACL for it.
  524  */
  525 int
  526 sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
  527 {
  528 
  529         return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
  530             FOLLOW));
  531 }
  532 
  533 /*
  534  * Given a file path, check an ACL for it; don't follow links.
  535  */
  536 int
  537 sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
  538 {
  539         return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
  540             NOFOLLOW));
  541 }
  542 
  543 static int
  544 kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type,
  545     struct acl *aclp, int follow)
  546 {
  547         struct nameidata nd;
  548         int error;
  549 
  550         NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path, td);
  551         error = namei(&nd);
  552         if (error == 0) {
  553                 error = vacl_aclcheck(td, nd.ni_vp, type, aclp);
  554                 NDFREE(&nd, 0);
  555         }
  556         return (error);
  557 }
  558 
  559 /*
  560  * Given a file descriptor, check an ACL for it.
  561  */
  562 int
  563 sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
  564 {
  565         struct file *fp;
  566         cap_rights_t rights;
  567         int error;
  568 
  569         AUDIT_ARG_FD(uap->filedes);
  570         error = getvnode(td, uap->filedes,
  571             cap_rights_init_one(&rights, CAP_ACL_CHECK), &fp);
  572         if (error == 0) {
  573                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
  574                 fdrop(fp, td);
  575         }
  576         return (error);
  577 }
  578 
  579 struct acl *
  580 acl_alloc(int flags)
  581 {
  582         struct acl *aclp;
  583 
  584         aclp = malloc(sizeof(*aclp), M_ACL, flags);
  585         if (aclp == NULL)
  586                 return (NULL);
  587 
  588         aclp->acl_maxcnt = ACL_MAX_ENTRIES;
  589 
  590         return (aclp);
  591 }
  592 
  593 void
  594 acl_free(struct acl *aclp)
  595 {
  596 
  597         free(aclp, M_ACL);
  598 }

Cache object: f6007bad9fb9a96c4bf6567c250680f3


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