freebsd-nq/sys/kern/kern_priv.c
Robert Watson 800c940832 Add a new priv(9) kernel interface for checking the availability of
privilege for threads and credentials.  Unlike the existing suser(9)
interface, priv(9) exposes a named privilege identifier to the privilege
checking code, allowing more complex policies regarding the granting of
privilege to be expressed.  Two interfaces are provided, replacing the
existing suser(9) interface:

suser(td)                 ->   priv_check(td, priv)
suser_cred(cred, flags)   ->   priv_check_cred(cred, priv, flags)

A comprehensive list of currently available kernel privileges may be
found in priv.h.  New privileges are easily added as required, but the
comments on adding privileges found in priv.h and priv(9) should be read
before doing so.

The new privilege interface exposed sufficient information to the
privilege checking routine that it will now be possible for jail to
determine whether a particular privilege is granted in the check routine,
rather than relying on hints from the calling context via the
SUSER_ALLOWJAIL flag.  For now, the flag is maintained, but a new jail
check function, prison_priv_check(), is exposed from kern_jail.c and used
by the privilege check routine to determine if the privilege is permitted
in jail.  As a result, a centralized list of privileges permitted in jail
is now present in kern_jail.c.

The MAC Framework is now also able to instrument privilege checks, both
to deny privileges otherwise granted (mac_priv_check()), and to grant
privileges otherwise denied (mac_priv_grant()), permitting MAC Policy
modules to implement privilege models, as well as control a much broader
range of system behavior in order to constrain processes running with
root privilege.

The suser() and suser_cred() functions remain implemented, now in terms
of priv_check() and the PRIV_ROOT privilege, for use during the transition
and possibly continuing use by third party kernel modules that have not
been updated.  The PRIV_DRIVER privilege exists to allow device drivers to
check privilege without adopting a more specific privilege identifier.

This change does not modify the actual security policy, rather, it
modifies the interface for privilege checks so changes to the security
policy become more feasible.

Sponsored by:		nCircle Network Security, Inc.
Obtained from:		TrustedBSD Project
Discussed on:		arch@
Reviewed (at least in part) by:	mlaier, jmg, pjd, bde, ceri,
			Alex Lyashkov <umka at sevcity dot net>,
			Skip Ford <skip dot ford at verizon dot net>,
			Antoine Brodin <antoine dot brodin at laposte dot net>
2006-11-06 13:37:19 +00:00

155 lines
4.8 KiB
C

/*-
* Copyright (c) 2006 nCircle Network Security, Inc.
* All rights reserved.
*
* This software was developed by Robert N. M. Watson for the TrustedBSD
* Project under contract to nCircle Network Security, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
* INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#include "opt_mac.h"
#include <sys/param.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <security/mac/mac_framework.h>
/*
* `suser_enabled' (which can be set by the security.bsd.suser_enabled
* sysctl) determines whether the system 'super-user' policy is in effect. If
* it is nonzero, an effective uid of 0 connotes special privilege,
* overriding many mandatory and discretionary protections. If it is zero,
* uid 0 is offered no special privilege in the kernel security policy.
* Setting it to zero may seriously impact the functionality of many existing
* userland programs, and should not be done without careful consideration of
* the consequences.
*/
int suser_enabled = 1;
SYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW,
&suser_enabled, 0, "processes with uid 0 have privilege");
TUNABLE_INT("security.bsd.suser_enabled", &suser_enabled);
/*
* Check a credential for privilege. Lots of good reasons to deny privilege;
* only a few to grant it.
*/
int
priv_check_cred(struct ucred *cred, int priv, int flags)
{
int error;
KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d",
priv));
#ifdef MAC
error = mac_priv_check(cred, priv);
if (error)
return (error);
#endif
/*
* Jail policy will restrict certain privileges that may otherwise be
* be granted.
*
* While debugging the transition from SUSER_ALLOWJAIL to Jail being
* aware of specific privileges, perform run-time checking that the
* two versions of the policy align. This assertion will go away
* once the SUSER_ALLOWJAIL flag has gone away.
*/
error = prison_priv_check(cred, priv);
#ifdef NOTYET
KASSERT(!jailed(cred) || error == ((flags & SUSER_ALLOWJAIL) ? 0 :
EPERM), ("priv_check_cred: prison_priv_check %d but flags %s",
error, flags & SUSER_ALLOWJAIL ? "allowjail" : "!allowjail"));
#endif
if (error)
return (error);
/*
* Having determined if privilege is restricted by various policies,
* now determine if privilege is granted. For now, we allow
* short-circuit boolean evaluation, so may not call all policies.
* Perhaps we should.
*
* Superuser policy grants privilege based on the effective (or in
* certain edge cases, real) uid being 0. We allow the policy to be
* globally disabled, although this is currently of limited utility.
*/
if (suser_enabled) {
if (flags & SUSER_RUID) {
if (cred->cr_ruid == 0)
return (0);
} else {
if (cred->cr_uid == 0)
return (0);
}
}
/*
* Now check with MAC, if enabled, to see if a policy module grants
* privilege.
*/
#ifdef MAC
if (mac_priv_grant(cred, priv) == 0)
return (0);
#endif
return (EPERM);
}
int
priv_check(struct thread *td, int priv)
{
KASSERT(td == curthread, ("priv_check: td != curthread"));
return (priv_check_cred(td->td_ucred, priv, 0));
}
/*
* Historical suser() wrapper functions, which now simply request PRIV_ROOT.
* These will be removed in the near future, and exist solely because
* the kernel and modules are not yet fully adapted to the new model.
*/
int
suser_cred(struct ucred *cred, int flags)
{
return (priv_check_cred(cred, PRIV_ROOT, flags));
}
int
suser(struct thread *td)
{
KASSERT(td == curthread, ("suser: td != curthread"));
return (suser_cred(td->td_ucred, 0));
}