e40c6b13a0
some tiny markup fix in secmodel_bsd44(9).
388 lines
12 KiB
Groff
388 lines
12 KiB
Groff
.\" $NetBSD: secmodel.9,v 1.6 2006/09/19 19:22:05 elad Exp $
|
|
.\"
|
|
.\" Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" 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.
|
|
.\" 3. All advertising materials mentioning features or use of this software
|
|
.\" must display the following acknowledgement:
|
|
.\" This product includes software developed by Elad Efrat.
|
|
.\" 4. The name of the author may not be used to endorse or promote products
|
|
.\" derived from this software without specific prior written permission.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
|
|
.\"
|
|
.Dd September 19, 2006
|
|
.Dt SECMODEL 9
|
|
.Os
|
|
.Sh NAME
|
|
.Nm secmodel
|
|
.Nd security model development guidelines
|
|
.Sh SYNOPSIS
|
|
.In secmodel/secmodel.h
|
|
.Sh DESCRIPTION
|
|
.Nx
|
|
provides a complete abstraction of the underlying security model used with
|
|
the operating system to a set of
|
|
.Xr kauth 9
|
|
scopes and actions.
|
|
.Pp
|
|
It is possible to modify the security model -- either slightly or using an
|
|
entirely different model -- by attaching/detaching
|
|
.Xr kauth 9
|
|
listeners.
|
|
This document describes this process.
|
|
.Ss Background
|
|
In
|
|
.Nx 4.0 ,
|
|
Kernel Authorization --
|
|
.Xr kauth 9
|
|
-- was introduced as the subsystem responsible for authorization and
|
|
credential management.
|
|
Before its introduction, there were several ways for providing resource access
|
|
control:
|
|
.Bl -dash -offset indent -compact
|
|
.It
|
|
Checking if the user in question is the superuser via
|
|
.Fn suser .
|
|
.It
|
|
Comparing the user-id against hard-coded values, often zero,
|
|
.It
|
|
Checking the system securelevel.
|
|
.El
|
|
.Pp
|
|
The problem with the above is that the interface ("can X do Y?") was
|
|
tightly coupled with the implementation ("is X Z?").
|
|
.Xr kauth 9
|
|
allowed us to separate them, dispatching requests with highly detailed
|
|
context using
|
|
a consistent and clear KPI.
|
|
.Pp
|
|
The result is a pluggable framework for attaching "listeners" that can
|
|
modify the behavior of the system, security-wise.
|
|
It allows us to maintain the existing security model (based on a single
|
|
superuser and above-superuser restrictions known as securelevel) but easily
|
|
decouple it from the system, given we want to use a different one.
|
|
.Pp
|
|
The different security model can be implemented in the kernel or loaded as an
|
|
LKM, base its decisions on available information, dispatch the decision to a
|
|
userspace daemon, or even to a centralized network authorization server.
|
|
.Ss The kauth(9) KPI
|
|
Before writing a new security model, one should be familiar with the
|
|
.Xr kauth 9
|
|
KPI, its limitations, requirements, and so on.
|
|
.Pp
|
|
First, some terminology.
|
|
According to
|
|
.Xr kauth 9 ,
|
|
the system is logically divided to scopes, where each scope denotes a
|
|
different area of interest in the system -- something like a namespace.
|
|
For example,
|
|
.Nx
|
|
has the process, network, and machdep scopes, representing process-related,
|
|
network-related, and machdep-related actions.
|
|
.Pp
|
|
Each scope has a collection of actions -- or requests -- forming the high
|
|
level indication of the request type.
|
|
Each request is automatically associated with credentials and between zero
|
|
to four arguments providing the request context.
|
|
.Pp
|
|
For example, in the process scope there are requests such as "can signal",
|
|
"can change rlimits", and "can change corename".
|
|
.Pp
|
|
Each scope in the system is associated with listeners, which are actually
|
|
callback routines, that get called when an authorization request on the
|
|
relevant scope takes place.
|
|
.Pp
|
|
Every listener receives the request and its context, and can make a decision
|
|
of either "allow", "deny", or "defer" (if it doesn't want to be the one
|
|
deciding).
|
|
.Pp
|
|
It is important to note that a single "deny" is enough to fail a request,
|
|
and at least a single "allow" is required to allow it.
|
|
In other words, it is impossible to attach listeners that weaken the security
|
|
of the system or override decisions made by other listeners.
|
|
.Pp
|
|
At last, there are several things you should remember about
|
|
.Xr kauth 9 :
|
|
.Bl -dash -offset indent
|
|
.It
|
|
Authorization requests can not be issued when the kernel is holding any
|
|
locks.
|
|
This is a requirement from kernel code, to allow designing security models
|
|
where the request should be dispatched to userspace or a different host.
|
|
.It
|
|
Private listener data -- such as internal data-structures -- is entirely
|
|
under the resonsibility of the developer.
|
|
Locking, synchronization, and garbage collection are all things that
|
|
.Xr kauth 9
|
|
does
|
|
.Em not
|
|
take care of for you!
|
|
.El
|
|
.Ss Writing a new security model
|
|
A security model is composed of (code-wise) the following components:
|
|
.Bl -enum -offset indent
|
|
.It
|
|
A
|
|
.Fn secmodel_start
|
|
routine, receiving and returning void.
|
|
This routine registers the various listeners for the security model.
|
|
.It
|
|
An "init" routine, named
|
|
.Fn secmodel_\*[Lt]model\*[Gt]_init ,
|
|
receiving and returning void.
|
|
This routine is used to initialize any private data-structures that may be
|
|
used by the model.
|
|
If none exist, it can be omitted.
|
|
It should be called from
|
|
.Fn secmodel_start .
|
|
.It
|
|
A sysctl(9) setup routine for the model.
|
|
This should create an entry for the model in the
|
|
.Xr sysctl 9
|
|
namespace, under the "security.models.\*[Lt]model\*[Gt]" hierarchy.
|
|
.It
|
|
All "knobs" for the model should be located under the new node, as well
|
|
as a mandatory "name" variable, indicating a descriptive human-readable
|
|
name for the model.
|
|
.It
|
|
Optionally, internal data-structures used by the model. These must all
|
|
be prefixed with "secmodel_\*[Lt]model\*[Lt]_".
|
|
.It
|
|
A set of listeners, attached to various scopes, used to enforce the policy
|
|
the model intends to implement.
|
|
.El
|
|
.Pp
|
|
Below is sample code for a
|
|
.Xr kauth 9
|
|
network scope listener for the
|
|
.Em jenna
|
|
security model.
|
|
It is used to allow users with a user-id below 1000 bind to reserved ports
|
|
(for example, 22/TCP):
|
|
.Bd -literal -offset indent
|
|
int
|
|
secmodel_jenna_network_cb(kauth_cred_t cred, kauth_action_t action,
|
|
void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
|
|
{
|
|
int result;
|
|
|
|
/* Default defer. */
|
|
result = KAUTH_RESULT_DEFER;
|
|
|
|
switch (action) {
|
|
case KAUTH_NETWORK_BIND:
|
|
/*
|
|
* We only care about bind(2) requests to privileged
|
|
* ports.
|
|
*/
|
|
if ((u_long)arg0 == KAUTH_REQ_NETWORK_BIND_PRIVPORT) {
|
|
/*
|
|
* If the user-id is below 1000, which may
|
|
* indicate a "reserved" user-id, allow the
|
|
* request.
|
|
*/
|
|
if (kauth_cred_geteuid(cred) \*[Lt] 1000)
|
|
result = KAUTH_RESULT_ALLOW;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
.Ed
|
|
.Pp
|
|
There are two main issues, however, with that listener, that you should be
|
|
aware of when approaching to write your own security model:
|
|
.Bl -enum -offset indent
|
|
.It
|
|
As mentioned,
|
|
.Xr kauth 9
|
|
uses restrictive decisions: if you attach this listener on-top of an existing
|
|
security model, even if it would allow the request, it could still be failed.
|
|
.It
|
|
If you attach this listener as the only listener for the network scope,
|
|
there are many other requests that will be deferred and, eventually,
|
|
denied -- which may not be desired.
|
|
.El
|
|
.Pp
|
|
That's why before implementing listeners, it should be clear whether they
|
|
implement an entirely new from scratch security model, or add on-top of an
|
|
existing one.
|
|
.Ss Adding on-top of an existing security model
|
|
One of the shortcomings of
|
|
.Xr kauth 9
|
|
is that it does not provide any stacking mechanism, similar to Linux Security
|
|
Modules (LSM).
|
|
This, however, is considered a feature in reducing dependency on other people's
|
|
code.
|
|
.Pp
|
|
To properly "stack" minor adjustments on-top of an existing security model,
|
|
one could use one of two approaches:
|
|
.Bl -dash
|
|
.It
|
|
Registering an internal scope for the security model to be used as a
|
|
fall-back when requests are deferred.
|
|
.Pp
|
|
This requires the security model developer to add an internal scope for
|
|
every scope the model partly covers, and registering the fall-back
|
|
listeners to it.
|
|
In the model's listener(s) for the scope, when a defer decision is made, the
|
|
request is passed to be authorized on the internal scope, effectively using
|
|
the fall-back security model.
|
|
.Pp
|
|
Here's example code that implements the above:
|
|
.Bd -literal -offset indent
|
|
#include \*[Lt]secmodel/bsd44/bsd44.h\*[Gt]
|
|
|
|
/*
|
|
* Internal fall-back scope for the network scope.
|
|
*/
|
|
#define JENNA_ISCOPE_NETWORK "jenna.iscope.network"
|
|
static kauth_scope_t secmodel_jenna_iscope_network;
|
|
|
|
/*
|
|
* Jenna's entry point. Register internal scope for the network scope
|
|
* which we partly cover for fall-back authorization.
|
|
*/
|
|
void
|
|
secmodel_jenna_start(void)
|
|
{
|
|
secmodel_jenna_iscope_network = kauth_register_scope(
|
|
JENNA_ISCOPE_NETWORK, NULL, NULL);
|
|
|
|
kauth_listen_scope(JENNA_ISCOPE_NETWORK,
|
|
secmodel_bsd44_suser_network_cb, NULL);
|
|
kauth_listen_scope(JENNA_ISCOPE_NETWORK,
|
|
secmodel_bsd44_securelevel_network_cb, NULL);
|
|
}
|
|
|
|
/*
|
|
* Jenna sits on top of another model, effectively filtering requests.
|
|
* If it has nothing to say, it discards the request. This is a good
|
|
* example for fine-tuning a security model for a special need.
|
|
*/
|
|
int
|
|
secmodel_jenna_network_cb(kauth_cred_t cred, kauth_action_t action,
|
|
void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
|
|
{
|
|
int result;
|
|
|
|
/* Default defer. */
|
|
result = KAUTH_RESULT_DEFER;
|
|
|
|
switch (action) {
|
|
case KAUTH_NETWORK_BIND:
|
|
/*
|
|
* We only care about bind(2) requests to privileged
|
|
* ports.
|
|
*/
|
|
if ((u_long)arg0 == KAUTH_REQ_NETWORK_BIND_PRIVPORT) {
|
|
if (kauth_cred_geteuid(cred) \*[Lt] 1000)
|
|
result = KAUTH_RESULT_ALLOW;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If we have don't have a decision, fall-back to the bsd44
|
|
* security model.
|
|
*/
|
|
if (result == KAUTH_RESULT_DEFER)
|
|
result = kauth_authorize_action(
|
|
secmodel_jenna_iscope_network, cred, action,
|
|
arg0, arg1, arg2, arg3);
|
|
|
|
return (result);
|
|
}
|
|
.Ed
|
|
.It
|
|
If the above is not desired, or cannot be used for any reason, there is
|
|
always the ability to manually call the fall-back routine:
|
|
.Bd -literal -offset indent
|
|
int
|
|
secmodel_jenna_network_cb(kauth_cred_t cred, kauth_action_t action,
|
|
void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
|
|
{
|
|
int result;
|
|
|
|
/* Default defer. */
|
|
result = KAUTH_RESULT_DEFER;
|
|
|
|
switch (action) {
|
|
case KAUTH_NETWORK_BIND:
|
|
/*
|
|
* We only care about bind(2) requests to privileged
|
|
* ports.
|
|
*/
|
|
if ((u_long)arg0 == KAUTH_REQ_NETWORK_BIND_PRIVPORT) {
|
|
if (kauth_cred_geteuid(cred) \*[Lt] 1000)
|
|
result = KAUTH_RESULT_ALLOW;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If we have don't have a decision, fall-back to the bsd44
|
|
* security model's suser behavior.
|
|
*/
|
|
if (result == KAUTH_RESULT_DEFER)
|
|
result = secmodel_bsd44_suser_network_cb(cred, action,
|
|
cookie, arg0, arg1, arg2, arg3);
|
|
|
|
return (result);
|
|
}
|
|
.Ed
|
|
.El
|
|
.Ss Writing a new security model from scratch
|
|
When writing a security model from scratch, aside from the obvious issues of
|
|
carefully following the desired policy to be implemented and paying attention
|
|
to all of the issues outlined above, one must also remember that any unhandled
|
|
requests will be denied by default.
|
|
.Pp
|
|
To make it easier on developers to write new security models from scratch,
|
|
.Nx
|
|
maintains skeleton listeners that contain every possible request and
|
|
arguments.
|
|
.Ss Available security models
|
|
The following is a list of security models available in the default
|
|
.Nx
|
|
distribution.
|
|
To choose, one should edit
|
|
.Pa /usr/src/sys/conf/std .
|
|
.Bl -tag -hyphen
|
|
.It secmodel_bsd44
|
|
Traditional
|
|
.Nx
|
|
security model, derived from
|
|
.Bx 4.4 .
|
|
.It secmodel_overlay
|
|
Sample overlay security model, sitting on-top of
|
|
.Xr secmodel_bsd44 9 .
|
|
.El
|
|
.Sh FILES
|
|
.Pa /usr/share/examples/secmodel
|
|
.Sh SEE ALSO
|
|
.Xr kauth 9 ,
|
|
.Xr secmodel_bsd44 9 ,
|
|
.Xr secmodel_overlay 9
|
|
.Sh AUTHORS
|
|
.An Elad Efrat Aq elad@NetBSD.org
|