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/kern_priv.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) 2006 nCircle Network Security, Inc.
    5  * Copyright (c) 2009 Robert N. M. Watson
    6  * Copyright (c) 2020 Mariusz Zaborski <oshogbo@FreeBSD.org>
    7  * All rights reserved.
    8  *
    9  * This software was developed by Robert N. M. Watson for the TrustedBSD
   10  * Project under contract to nCircle Network Security, Inc.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
   25  * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
   27  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/jail.h>
   39 #include <sys/kernel.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/sx.h>
   43 #include <sys/priv.h>
   44 #include <sys/proc.h>
   45 #include <sys/sdt.h>
   46 #include <sys/sysctl.h>
   47 #include <sys/systm.h>
   48 
   49 #include <security/mac/mac_framework.h>
   50 
   51 /*
   52  * `suser_enabled' (which can be set by the security.bsd.suser_enabled
   53  * sysctl) determines whether the system 'super-user' policy is in effect.  If
   54  * it is nonzero, an effective uid of 0 connotes special privilege,
   55  * overriding many mandatory and discretionary protections.  If it is zero,
   56  * uid 0 is offered no special privilege in the kernel security policy.
   57  * Setting it to zero may seriously impact the functionality of many existing
   58  * userland programs, and should not be done without careful consideration of
   59  * the consequences.
   60  */
   61 
   62 static bool
   63 suser_enabled(struct ucred *cred)
   64 {
   65 
   66         return (prison_allow(cred, PR_ALLOW_SUSER));
   67 }
   68 
   69 static int
   70 sysctl_kern_suser_enabled(SYSCTL_HANDLER_ARGS)
   71 {
   72         struct ucred *cred;
   73         int error, enabled;
   74 
   75         cred = req->td->td_ucred;
   76         enabled = suser_enabled(cred);
   77         error = sysctl_handle_int(oidp, &enabled, 0, req);
   78         if (error || !req->newptr)
   79                 return (error);
   80         prison_set_allow(cred, PR_ALLOW_SUSER, enabled);
   81         return (0);
   82 }
   83 
   84 SYSCTL_PROC(_security_bsd, OID_AUTO, suser_enabled, CTLTYPE_INT |
   85     CTLFLAG_RWTUN | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 0, 0,
   86     &sysctl_kern_suser_enabled, "I", "Processes with uid 0 have privilege");
   87 
   88 static int      unprivileged_mlock = 1;
   89 SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_mlock, CTLFLAG_RWTUN,
   90     &unprivileged_mlock, 0, "Allow non-root users to call mlock(2)");
   91 
   92 static int      unprivileged_read_msgbuf = 1;
   93 SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
   94     CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
   95     "Unprivileged processes may read the kernel message buffer");
   96 
   97 SDT_PROVIDER_DEFINE(priv);
   98 SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int");
   99 SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int");
  100 
  101 static __always_inline int
  102 priv_check_cred_pre(struct ucred *cred, int priv)
  103 {
  104         int error;
  105 
  106 #ifdef MAC
  107         error = mac_priv_check(cred, priv);
  108 #else
  109         error = 0;
  110 #endif
  111         return (error);
  112 }
  113 
  114 static __always_inline int
  115 priv_check_cred_post(struct ucred *cred, int priv, int error, bool handled)
  116 {
  117 
  118         if (__predict_true(handled))
  119                 goto out;
  120         /*
  121          * Now check with MAC, if enabled, to see if a policy module grants
  122          * privilege.
  123          */
  124 #ifdef MAC
  125         if (mac_priv_grant(cred, priv) == 0) {
  126                 error = 0;
  127                 goto out;
  128         }
  129 #endif
  130 
  131         /*
  132          * The default is deny, so if no policies have granted it, reject
  133          * with a privilege error here.
  134          */
  135         error = EPERM;
  136 out:
  137         if (SDT_PROBES_ENABLED()) {
  138                 if (error)
  139                         SDT_PROBE1(priv, kernel, priv_check, priv__err, priv);
  140                 else
  141                         SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv);
  142         }
  143         return (error);
  144 }
  145 
  146 /*
  147  * Check a credential for privilege.  Lots of good reasons to deny privilege;
  148  * only a few to grant it.
  149  */
  150 int
  151 priv_check_cred(struct ucred *cred, int priv)
  152 {
  153         int error;
  154 
  155         KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d",
  156             priv));
  157 
  158         switch (priv) {
  159         case PRIV_VFS_LOOKUP:
  160                 return (priv_check_cred_vfs_lookup(cred));
  161         case PRIV_VFS_GENERATION:
  162                 return (priv_check_cred_vfs_generation(cred));
  163         }
  164 
  165         /*
  166          * We first evaluate policies that may deny the granting of
  167          * privilege unilaterally.
  168          */
  169         error = priv_check_cred_pre(cred, priv);
  170         if (error)
  171                 goto out;
  172 
  173         /*
  174          * Jail policy will restrict certain privileges that may otherwise be
  175          * be granted.
  176          */
  177         error = prison_priv_check(cred, priv);
  178         if (error)
  179                 goto out;
  180 
  181         if (unprivileged_mlock) {
  182                 /*
  183                  * Allow unprivileged users to call mlock(2)/munlock(2) and
  184                  * mlockall(2)/munlockall(2).
  185                  */
  186                 switch (priv) {
  187                 case PRIV_VM_MLOCK:
  188                 case PRIV_VM_MUNLOCK:
  189                         error = 0;
  190                         goto out;
  191                 }
  192         }
  193 
  194         if (unprivileged_read_msgbuf) {
  195                 /*
  196                  * Allow an unprivileged user to read the kernel message
  197                  * buffer.
  198                  */
  199                 if (priv == PRIV_MSGBUF) {
  200                         error = 0;
  201                         goto out;
  202                 }
  203         }
  204 
  205         /*
  206          * Having determined if privilege is restricted by various policies,
  207          * now determine if privilege is granted.  At this point, any policy
  208          * may grant privilege.  For now, we allow short-circuit boolean
  209          * evaluation, so may not call all policies.  Perhaps we should.
  210          *
  211          * Superuser policy grants privilege based on the effective (or in
  212          * the case of specific privileges, real) uid being 0.  We allow the
  213          * superuser policy to be globally disabled, although this is
  214          * currenty of limited utility.
  215          */
  216         if (suser_enabled(cred)) {
  217                 switch (priv) {
  218                 case PRIV_MAXFILES:
  219                 case PRIV_MAXPROC:
  220                 case PRIV_PROC_LIMIT:
  221                         if (cred->cr_ruid == 0) {
  222                                 error = 0;
  223                                 goto out;
  224                         }
  225                         break;
  226                 case PRIV_VFS_READ_DIR:
  227                         /*
  228                          * Allow PRIV_VFS_READ_DIR for root if we're not in a
  229                          * jail, otherwise deny unless a MAC policy grants it.
  230                          */
  231                         if (jailed(cred))
  232                                 break;
  233                         /* FALLTHROUGH */
  234                 default:
  235                         if (cred->cr_uid == 0) {
  236                                 error = 0;
  237                                 goto out;
  238                         }
  239                         break;
  240                 }
  241         }
  242 
  243         /*
  244          * Writes to kernel/physical memory are a typical root-only operation,
  245          * but non-root users are expected to be able to read it (provided they
  246          * have permission to access /dev/[k]mem).
  247          */
  248         if (priv == PRIV_KMEM_READ) {
  249                 error = 0;
  250                 goto out;
  251         }
  252 
  253         /*
  254          * Allow unprivileged process debugging on a per-jail basis.
  255          * Do this here instead of prison_priv_check(), so it can also
  256          * apply to prison0.
  257          */
  258         if (priv == PRIV_DEBUG_UNPRIV) {
  259                 if (prison_allow(cred, PR_ALLOW_UNPRIV_DEBUG)) {
  260                         error = 0;
  261                         goto out;
  262                 }
  263         }
  264 
  265         return (priv_check_cred_post(cred, priv, error, false));
  266 out:
  267         return (priv_check_cred_post(cred, priv, error, true));
  268 }
  269 
  270 int
  271 priv_check(struct thread *td, int priv)
  272 {
  273 
  274         KASSERT(td == curthread, ("priv_check: td != curthread"));
  275 
  276         return (priv_check_cred(td->td_ucred, priv));
  277 }
  278 
  279 static int __noinline
  280 priv_check_cred_vfs_lookup_slow(struct ucred *cred)
  281 {
  282         int error;
  283 
  284         error = priv_check_cred_pre(cred, PRIV_VFS_LOOKUP);
  285         if (error)
  286                 goto out;
  287 
  288         if (cred->cr_uid == 0 && suser_enabled(cred)) {
  289                 error = 0;
  290                 goto out;
  291         }
  292 
  293         return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, false));
  294 out:
  295         return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, true));
  296 
  297 }
  298 
  299 int
  300 priv_check_cred_vfs_lookup(struct ucred *cred)
  301 {
  302         int error;
  303 
  304         if (__predict_false(mac_priv_check_fp_flag ||
  305             mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
  306                 return (priv_check_cred_vfs_lookup_slow(cred));
  307 
  308         error = EPERM;
  309         if (cred->cr_uid == 0 && suser_enabled(cred))
  310                 error = 0;
  311         return (error);
  312 }
  313 
  314 int
  315 priv_check_cred_vfs_lookup_nomac(struct ucred *cred)
  316 {
  317         int error;
  318 
  319         if (__predict_false(mac_priv_check_fp_flag ||
  320             mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
  321                 return (EAGAIN);
  322 
  323         error = EPERM;
  324         if (cred->cr_uid == 0 && suser_enabled(cred))
  325                 error = 0;
  326         return (error);
  327 }
  328 
  329 static int __noinline
  330 priv_check_cred_vfs_generation_slow(struct ucred *cred)
  331 {
  332         int error;
  333 
  334         error = priv_check_cred_pre(cred, PRIV_VFS_GENERATION);
  335         if (error)
  336                 goto out;
  337 
  338         if (jailed(cred)) {
  339                 error = EPERM;
  340                 goto out;
  341         }
  342 
  343         if (cred->cr_uid == 0 && suser_enabled(cred)) {
  344                 error = 0;
  345                 goto out;
  346         }
  347 
  348         return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, false));
  349 out:
  350         return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, true));
  351 
  352 }
  353 
  354 int
  355 priv_check_cred_vfs_generation(struct ucred *cred)
  356 {
  357         int error;
  358 
  359         if (__predict_false(mac_priv_check_fp_flag ||
  360             mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
  361                 return (priv_check_cred_vfs_generation_slow(cred));
  362 
  363         error = EPERM;
  364         if (!jailed(cred) && cred->cr_uid == 0 && suser_enabled(cred))
  365                 error = 0;
  366         return (error);
  367 }

Cache object: f0d3ccfc64a6647742560c095188256a


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