539 lines
14 KiB
Groff
539 lines
14 KiB
Groff
.\" $NetBSD: secmodel.9,v 1.19 2013/07/20 21:39:59 wiz 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. 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 December 4, 2011
|
|
.Dt SECMODEL 9
|
|
.Os
|
|
.Sh NAME
|
|
.Nm secmodel
|
|
.Nd security model development guidelines
|
|
.Sh SYNOPSIS
|
|
.In secmodel/secmodel.h
|
|
.Ft int
|
|
.Fn secmodel_register "secmodel_t *sm" "const char *id" "const char *name" \
|
|
"prop_dictionary_t behavior" "secmodel_eval_t sm_eval" \
|
|
"secmodel_setinfo_t sm_setinfo"
|
|
.Ft int
|
|
.Fn secmodel_deregister "secmodel_t sm"
|
|
.Ft int
|
|
.Fn secmodel_eval "const char *id" "const char *what" "void *arg" "void *ret"
|
|
.Ft static int
|
|
.Fn secmodel_\*[Lt]model\*[Gt]_eval "const char *what" "void *arg" \
|
|
"void *ret"
|
|
.Sh DESCRIPTION
|
|
.Nx
|
|
provides a complete abstraction of the underlying security model used within
|
|
the operating system through a set of
|
|
.Xr kauth 9
|
|
scopes and actions.
|
|
It allows maintaining the traditional security model (based on a single
|
|
.Em super-user
|
|
and above-super-user restrictions known as
|
|
.Em securelevel )
|
|
while decoupling it easily from the system.
|
|
.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 can be done via the
|
|
.Nm
|
|
pluggable framework.
|
|
.Pp
|
|
A
|
|
.Nm
|
|
is typically implemented as a kernel
|
|
.Xr module 9 ,
|
|
and can be either built-in statically or loaded dynamically at run-time.
|
|
They base their decisions on available information, either directly from
|
|
kernel, from a userspace daemon or even from a centralized network
|
|
authorization server.
|
|
.Sh DATA TYPES
|
|
The
|
|
.Nm
|
|
framework offers the following data types:
|
|
.Bl -tag -width secmodel_t
|
|
.It Fa secmodel_t
|
|
An opaque type that describes a
|
|
.Nm .
|
|
.El
|
|
.Sh FUNCTIONS
|
|
.Bl -tag -width xxxxxxx
|
|
.It Fn secmodel_register "sm" "id" "name" "behavior" "sm_eval" "sm_setinfo"
|
|
Register a security model to the
|
|
.Nm
|
|
framework and stores its description inside
|
|
.Fa sm .
|
|
.Bl -tag -width sm_setinfo
|
|
.It Fa sm
|
|
The
|
|
.Nm
|
|
description.
|
|
.It Fa id
|
|
The unique identifier of the
|
|
.Nm .
|
|
.It Fa name
|
|
The descriptive human-readable name of the
|
|
.Nm .
|
|
.It Fa behavior
|
|
(optional) a
|
|
.Xr prop_dictionary 3
|
|
that declares the behavior of this security model, like
|
|
.Do copy credentials on fork . Dc
|
|
.It Fa sm_eval
|
|
(optional) the
|
|
.Fn secmodel_\*[Lt]model\*[Gt]_eval
|
|
callback used by a
|
|
.Nm
|
|
to register an evaluation routine that can be queried later
|
|
by another security model.
|
|
.It Fa sm_setinfo
|
|
(optional) the
|
|
.Fn secmodel_\*[Lt]model\*[Gt]_setinfo
|
|
callback used by a
|
|
.Nm
|
|
to register a routine that permits other security models to
|
|
alter the
|
|
.Nm
|
|
internals.
|
|
Currently not implemented.
|
|
.El
|
|
.It Fn secmodel_deregister "sm"
|
|
Deregister the
|
|
.Nm
|
|
described by
|
|
.Fa sm .
|
|
.It Fn secmodel_eval "id" "what" "arg" "ret"
|
|
Call the evaluation callback implemented by a security model.
|
|
The return value can be either:
|
|
.Bl -dash -compact -offset xxxxxx
|
|
.It
|
|
zero (0), when the call succeeded.
|
|
.It
|
|
positive, when the error comes directly from the
|
|
.Nm
|
|
framework.
|
|
.It
|
|
negative, when the error comes from the evaluation callback
|
|
implemented in the targetted security model.
|
|
The value is then implementation-defined.
|
|
.El
|
|
.Pp
|
|
.Bl -tag -width what
|
|
.It Fa id
|
|
The unique identifier of the targetted
|
|
.Nm .
|
|
.It Fa what
|
|
The query that will be passed down to the targetted
|
|
.Nm .
|
|
.It Fa arg
|
|
The arguments passed to the evaluation routine of the targetted
|
|
.Nm .
|
|
.It Fa ret
|
|
The answer of the evaluation routine.
|
|
.El
|
|
.El
|
|
.Sh RETURN VALUES
|
|
If successful, functions return 0.
|
|
Otherwise, the following error values are returned:
|
|
.Bl -tag -width [EINVAL]
|
|
.It Bq Er EEXIST
|
|
The
|
|
.Nm
|
|
is already registered.
|
|
.It Bq Er EFAULT
|
|
An invalid address or reference was passed as parameter.
|
|
.It Bq Er EINVAL
|
|
An invalid value was passed as parameter.
|
|
.It Bq Er ENOENT
|
|
The targetted
|
|
.Nm
|
|
does not exist, or it does not implement an evaluation callback.
|
|
.El
|
|
.Sh WRITING A SECURITY MODEL
|
|
Before writing a security model one should be familiar with the
|
|
.Xr kauth 9
|
|
KPI, its limitations, requirements, and so on.
|
|
See
|
|
.Xr kauth 9
|
|
for details.
|
|
.Pp
|
|
A security model is based on the kernel
|
|
.Xr module 9
|
|
framework, and can be built-in statically inside kernel or
|
|
loaded dynamically at run-time.
|
|
It is composed of (code-wise) the following components:
|
|
.Bl -enum -offset indent
|
|
.It
|
|
.Xr module 9
|
|
routines, especially a
|
|
.Fn MODULE
|
|
declaration and a
|
|
.Fn secmodel_\*[Lt]model\*[Gt]_modcmd
|
|
function used to start
|
|
.Po through Dv MODULE_CMD_INIT Pc
|
|
and stop
|
|
.Po through Dv MODULE_CMD_FINI Pc
|
|
the
|
|
.Nm .
|
|
.It
|
|
Entry routines, named
|
|
.Fn secmodel_\*[Lt]model\*[Gt]_init
|
|
and
|
|
.Fn secmodel_\*[Lt]model\*[Gt]_start ,
|
|
used to initialize and start the security model, and another
|
|
function called
|
|
.Fn secmodel_\*[Lt]model\*[Gt]_stop ,
|
|
to stop the security model in case the module is to be unloaded.
|
|
.It
|
|
A
|
|
.Xr sysctl 9
|
|
setup routine for the model.
|
|
This should create an entry for the model in the
|
|
.Xr sysctl 7
|
|
namespace, under the "security.models.\*[Lt]model\*[Gt]" hierarchy.
|
|
.Pp
|
|
All "knobs" for the model should be located under the new node, as well
|
|
as a mandatory
|
|
.Fa name
|
|
variable, indicating a descriptive human-readable
|
|
name for the model.
|
|
.It
|
|
A
|
|
.Xr sysctl 9
|
|
teardown routine used to destroy the
|
|
.Xr sysctl 7
|
|
tree associated with the model.
|
|
.It
|
|
If the model uses any private data inside credentials, listening on
|
|
the credentials scope,
|
|
.Dv KAUTH_SCOPE_CRED ,
|
|
is required.
|
|
.It
|
|
Optionally, internal data-structures used by the model.
|
|
These must all be prefixed with "secmodel_\*[Lt]model\*[Gt]_".
|
|
.It
|
|
A set of listeners, attached to various scopes, used to enforce the policy
|
|
the model intends to implement.
|
|
.It
|
|
Finally, a security model should register itself after being
|
|
initialized using
|
|
.Fn secmodel_register ,
|
|
and deregister itself before being stopped using
|
|
.Fn secmodel_deregister .
|
|
.El
|
|
.Sh EXAMPLES
|
|
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 to bind to reserved ports
|
|
(for example, 22/TCP):
|
|
.Bd -literal
|
|
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
|
|
.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 denied.
|
|
.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.
|
|
.Sh PROGRAMMING CONSIDERATIONS
|
|
There are several things you should remember when writing a security model:
|
|
.Bl -dash -offset indent
|
|
.It
|
|
Pay attention to the correctness of your
|
|
.Nm
|
|
implementation of the desired policy.
|
|
Certain rights can grant more privileges on the system than others,
|
|
like allowing calls to
|
|
.Xr chroot 2
|
|
or mounting a file-system.
|
|
.It
|
|
All unhandled requests are denied by default.
|
|
.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 responsibility 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 STACKING ON 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 -enum
|
|
.It
|
|
Register 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 register 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 is example code that implements the above:
|
|
.Bd -literal
|
|
#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_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
|
|
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
|
|
.Sh AVAILABLE SECURITY MODELS
|
|
The following is a list of security models available in the default
|
|
.Nx
|
|
distribution.
|
|
.Bl -tag -width xxxxxxxx
|
|
.It Xr secmodel_suser 9
|
|
Implements the
|
|
.Em super-user
|
|
(root) security policy.
|
|
.It Xr secmodel_securelevel 9
|
|
Implements the
|
|
.Em securelevel
|
|
security model.
|
|
.It Xr secmodel_extensions 9
|
|
Implements extensions to the traditional
|
|
.Bx 4.4
|
|
security model, like usermounts.
|
|
.It Xr secmodel_bsd44 9
|
|
Traditional
|
|
.Nx
|
|
security model, derived from
|
|
.Bx 4.4 .
|
|
.It Xr secmodel_overlay 9
|
|
Sample overlay security model, sitting on-top of
|
|
.Xr secmodel_bsd44 9 .
|
|
.El
|
|
.Sh CODE REFERENCES
|
|
The core of the
|
|
.Nm
|
|
implementation is in
|
|
.Pa sys/secmodel/secmodel.c .
|
|
.Pp
|
|
The header file
|
|
.In secmodel/secmodel.h
|
|
describes the public interface.
|
|
.Pp
|
|
To make it easier on developers to write new security models from scratch,
|
|
.Nx
|
|
maintains an example
|
|
.Nm
|
|
under
|
|
.Pa share/examples/secmodel/ .
|
|
.Sh SEE ALSO
|
|
.Xr kauth 9 ,
|
|
.Xr module 9 ,
|
|
.Xr secmodel_bsd44 9 ,
|
|
.Xr secmodel_extensions 9 ,
|
|
.Xr secmodel_overlay 9 ,
|
|
.Xr secmodel_securelevel 9 ,
|
|
.Xr secmodel_suser 9
|
|
.Sh HISTORY
|
|
Kernel Authorization was introduced in
|
|
.Nx 4.0
|
|
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 super-user 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
|
|
allows separating them, dispatching requests with highly detailed
|
|
context using a consistent and clear KPI.
|
|
.Pp
|
|
The
|
|
.Nm
|
|
framework was extended in
|
|
.Nx 6.0
|
|
to implement
|
|
.Nm
|
|
registration and evaluation procedure calls.
|
|
.Sh AUTHORS
|
|
.An Elad Efrat Aq Mt elad@NetBSD.org
|