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/contrib/openzfs/module/os/linux/zfs/policy.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  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 
   22 /*
   23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
   24  * Copyright 2013, Joyent, Inc. All rights reserved.
   25  * Copyright (C) 2016 Lawrence Livermore National Security, LLC.
   26  *
   27  * For Linux the vast majority of this enforcement is already handled via
   28  * the standard Linux VFS permission checks.  However certain administrative
   29  * commands which bypass the standard mechanisms may need to make use of
   30  * this functionality.
   31  */
   32 
   33 #include <sys/policy.h>
   34 #include <linux/security.h>
   35 #include <linux/vfs_compat.h>
   36 
   37 /*
   38  * The passed credentials cannot be directly verified because Linux only
   39  * provides and interface to check the *current* process credentials.  In
   40  * order to handle this the capable() test is only run when the passed
   41  * credentials match the current process credentials or the kcred.  In
   42  * all other cases this function must fail and return the passed err.
   43  */
   44 static int
   45 priv_policy_ns(const cred_t *cr, int capability, int err,
   46     struct user_namespace *ns)
   47 {
   48         if (cr != CRED() && (cr != kcred))
   49                 return (err);
   50 
   51 #if defined(CONFIG_USER_NS)
   52         if (!(ns ? ns_capable(ns, capability) : capable(capability)))
   53 #else
   54         if (!capable(capability))
   55 #endif
   56                 return (err);
   57 
   58         return (0);
   59 }
   60 
   61 static int
   62 priv_policy(const cred_t *cr, int capability, int err)
   63 {
   64         return (priv_policy_ns(cr, capability, err, cr->user_ns));
   65 }
   66 
   67 static int
   68 priv_policy_user(const cred_t *cr, int capability, int err)
   69 {
   70         /*
   71          * All priv_policy_user checks are preceded by kuid/kgid_has_mapping()
   72          * checks. If we cannot do them, we shouldn't be using ns_capable()
   73          * since we don't know whether the affected files are valid in our
   74          * namespace.
   75          */
   76 #if defined(CONFIG_USER_NS)
   77         return (priv_policy_ns(cr, capability, err, cr->user_ns));
   78 #else
   79         return (priv_policy_ns(cr, capability, err, NULL));
   80 #endif
   81 }
   82 
   83 /*
   84  * Checks for operations that are either client-only or are used by
   85  * both clients and servers.
   86  */
   87 int
   88 secpolicy_nfs(const cred_t *cr)
   89 {
   90         return (priv_policy(cr, CAP_SYS_ADMIN, EPERM));
   91 }
   92 
   93 /*
   94  * Catch all system configuration.
   95  */
   96 int
   97 secpolicy_sys_config(const cred_t *cr, boolean_t checkonly)
   98 {
   99         return (priv_policy(cr, CAP_SYS_ADMIN, EPERM));
  100 }
  101 
  102 /*
  103  * Like secpolicy_vnode_access() but we get the actual wanted mode and the
  104  * current mode of the file, not the missing bits.
  105  *
  106  * Enforced in the Linux VFS.
  107  */
  108 int
  109 secpolicy_vnode_access2(const cred_t *cr, struct inode *ip, uid_t owner,
  110     mode_t curmode, mode_t wantmode)
  111 {
  112         return (0);
  113 }
  114 
  115 /*
  116  * This is a special routine for ZFS; it is used to determine whether
  117  * any of the privileges in effect allow any form of access to the
  118  * file.  There's no reason to audit this or any reason to record
  119  * this.  More work is needed to do the "KPLD" stuff.
  120  */
  121 int
  122 secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner)
  123 {
  124         if (crgetuid(cr) == owner)
  125                 return (0);
  126 
  127         if (zpl_inode_owner_or_capable(kcred->user_ns, ip))
  128                 return (0);
  129 
  130 #if defined(CONFIG_USER_NS)
  131         if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
  132                 return (EPERM);
  133 #endif
  134 
  135         if (priv_policy_user(cr, CAP_DAC_OVERRIDE, EPERM) == 0)
  136                 return (0);
  137 
  138         if (priv_policy_user(cr, CAP_DAC_READ_SEARCH, EPERM) == 0)
  139                 return (0);
  140 
  141         return (EPERM);
  142 }
  143 
  144 /*
  145  * Determine if subject can chown owner of a file.
  146  */
  147 int
  148 secpolicy_vnode_chown(const cred_t *cr, uid_t owner)
  149 {
  150         if (crgetuid(cr) == owner)
  151                 return (0);
  152 
  153 #if defined(CONFIG_USER_NS)
  154         if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
  155                 return (EPERM);
  156 #endif
  157 
  158         return (priv_policy_user(cr, CAP_FOWNER, EPERM));
  159 }
  160 
  161 /*
  162  * Determine if subject can change group ownership of a file.
  163  */
  164 int
  165 secpolicy_vnode_create_gid(const cred_t *cr)
  166 {
  167         return (priv_policy(cr, CAP_SETGID, EPERM));
  168 }
  169 
  170 /*
  171  * Policy determines whether we can remove an entry from a directory,
  172  * regardless of permission bits.
  173  */
  174 int
  175 secpolicy_vnode_remove(const cred_t *cr)
  176 {
  177         return (priv_policy(cr, CAP_FOWNER, EPERM));
  178 }
  179 
  180 /*
  181  * Determine that subject can modify the mode of a file.  allzone privilege
  182  * needed when modifying root owned object.
  183  */
  184 int
  185 secpolicy_vnode_setdac(const cred_t *cr, uid_t owner)
  186 {
  187         if (crgetuid(cr) == owner)
  188                 return (0);
  189 
  190 #if defined(CONFIG_USER_NS)
  191         if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
  192                 return (EPERM);
  193 #endif
  194 
  195         return (priv_policy_user(cr, CAP_FOWNER, EPERM));
  196 }
  197 
  198 /*
  199  * Are we allowed to retain the set-uid/set-gid bits when
  200  * changing ownership or when writing to a file?
  201  * "issuid" should be true when set-uid; only in that case
  202  * root ownership is checked (setgid is assumed).
  203  *
  204  * Enforced in the Linux VFS.
  205  */
  206 int
  207 secpolicy_vnode_setid_retain(struct znode *zp __maybe_unused, const cred_t *cr,
  208     boolean_t issuidroot)
  209 {
  210         return (priv_policy_user(cr, CAP_FSETID, EPERM));
  211 }
  212 
  213 /*
  214  * Determine that subject can set the file setgid flag.
  215  */
  216 int
  217 secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zuserns_t *mnt_ns,
  218     zuserns_t *fs_ns)
  219 {
  220         gid = zfs_gid_to_vfsgid(mnt_ns, fs_ns, gid);
  221 #if defined(CONFIG_USER_NS)
  222         if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid)))
  223                 return (EPERM);
  224 #endif
  225         if (crgetgid(cr) != gid && !groupmember(gid, cr))
  226                 return (priv_policy_user(cr, CAP_FSETID, EPERM));
  227 
  228         return (0);
  229 }
  230 
  231 /*
  232  * Determine if the subject can inject faults in the ZFS fault injection
  233  * framework.  Requires all privileges.
  234  */
  235 int
  236 secpolicy_zinject(const cred_t *cr)
  237 {
  238         return (priv_policy(cr, CAP_SYS_ADMIN, EACCES));
  239 }
  240 
  241 /*
  242  * Determine if the subject has permission to manipulate ZFS datasets
  243  * (not pools).  Equivalent to the SYS_MOUNT privilege.
  244  */
  245 int
  246 secpolicy_zfs(const cred_t *cr)
  247 {
  248         return (priv_policy(cr, CAP_SYS_ADMIN, EACCES));
  249 }
  250 
  251 /*
  252  * Equivalent to secpolicy_zfs(), but works even if the cred_t is not that of
  253  * the current process.  Takes both cred_t and proc_t so that this can work
  254  * easily on all platforms.
  255  *
  256  * The has_capability() function was first exported in the 4.10 Linux kernel
  257  * then backported to some LTS kernels.  Prior to this change there was no
  258  * mechanism to perform this check therefore EACCES is returned when the
  259  * functionality is not present in the kernel.
  260  */
  261 int
  262 secpolicy_zfs_proc(const cred_t *cr, proc_t *proc)
  263 {
  264 #if defined(HAVE_HAS_CAPABILITY)
  265         if (!has_capability(proc, CAP_SYS_ADMIN))
  266                 return (EACCES);
  267         return (0);
  268 #else
  269         return (EACCES);
  270 #endif
  271 }
  272 
  273 void
  274 secpolicy_setid_clear(vattr_t *vap, cred_t *cr)
  275 {
  276         if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 &&
  277             secpolicy_vnode_setid_retain(NULL, cr,
  278             (vap->va_mode & S_ISUID) != 0 &&
  279             (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) {
  280                 vap->va_mask |= AT_MODE;
  281                 vap->va_mode &= ~(S_ISUID|S_ISGID);
  282         }
  283 }
  284 
  285 /*
  286  * Determine that subject can set the file setid flags.
  287  */
  288 static int
  289 secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zuserns_t *mnt_ns,
  290     zuserns_t *fs_ns)
  291 {
  292         owner = zfs_uid_to_vfsuid(mnt_ns, fs_ns, owner);
  293 
  294         if (crgetuid(cr) == owner)
  295                 return (0);
  296 
  297 #if defined(CONFIG_USER_NS)
  298         if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
  299                 return (EPERM);
  300 #endif
  301 
  302         return (priv_policy_user(cr, CAP_FSETID, EPERM));
  303 }
  304 
  305 /*
  306  * Determine that subject can make a file a "sticky".
  307  *
  308  * Enforced in the Linux VFS.
  309  */
  310 static int
  311 secpolicy_vnode_stky_modify(const cred_t *cr)
  312 {
  313         return (0);
  314 }
  315 
  316 int
  317 secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap,
  318     const vattr_t *ovap, cred_t *cr, zuserns_t *mnt_ns, zuserns_t *fs_ns)
  319 {
  320         int error;
  321 
  322         if ((vap->va_mode & S_ISUID) != 0 &&
  323             (error = secpolicy_vnode_setid_modify(cr,
  324             ovap->va_uid, mnt_ns, fs_ns)) != 0) {
  325                 return (error);
  326         }
  327 
  328         /*
  329          * Check privilege if attempting to set the
  330          * sticky bit on a non-directory.
  331          */
  332         if (!S_ISDIR(ip->i_mode) && (vap->va_mode & S_ISVTX) != 0 &&
  333             secpolicy_vnode_stky_modify(cr) != 0) {
  334                 vap->va_mode &= ~S_ISVTX;
  335         }
  336 
  337         /*
  338          * Check for privilege if attempting to set the
  339          * group-id bit.
  340          */
  341         if ((vap->va_mode & S_ISGID) != 0 &&
  342             secpolicy_vnode_setids_setgids(cr, ovap->va_gid,
  343             mnt_ns, fs_ns) != 0) {
  344                 vap->va_mode &= ~S_ISGID;
  345         }
  346 
  347         return (0);
  348 }
  349 
  350 /*
  351  * Check privileges for setting xvattr attributes
  352  */
  353 int
  354 secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, mode_t type)
  355 {
  356         return (secpolicy_vnode_chown(cr, owner));
  357 }
  358 
  359 /*
  360  * Check privileges for setattr attributes.
  361  *
  362  * Enforced in the Linux VFS.
  363  */
  364 int
  365 secpolicy_vnode_setattr(cred_t *cr, struct inode *ip, struct vattr *vap,
  366     const struct vattr *ovap, int flags,
  367     int unlocked_access(void *, int, cred_t *), void *node)
  368 {
  369         return (0);
  370 }
  371 
  372 /*
  373  * Check privileges for links.
  374  *
  375  * Enforced in the Linux VFS.
  376  */
  377 int
  378 secpolicy_basic_link(const cred_t *cr)
  379 {
  380         return (0);
  381 }

Cache object: 3b5e884cbeff9b0aa63ce43d5d5b1206


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