| SECMODEL(9) | Kernel Developer's Manual | SECMODEL(9) |
secmodel —
security model development guidelines
#include
<secmodel/secmodel.h>
int
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);
int
secmodel_deregister(secmodel_t
sm);
int
secmodel_eval(const
char *id, const char
*what, void *arg,
void *ret);
static int
secmodel_<model>_eval(const
char *what, void
*arg, void
*ret);
NetBSD provides a complete abstraction of the underlying security model used within the operating system through a set of kauth(9) scopes and actions. It allows maintaining the traditional security model (based on a single super-user and above-super-user restrictions known as securelevel) while decoupling it easily from the system.
It is possible to modify the security model — either
slightly or using an entirely different model — by
attaching/detaching kauth(9)
listeners. This can be done via the secmodel
pluggable framework.
A secmodel is typically implemented as a
kernel 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.
The secmodel framework offers the
following data types:
secmodel.secmodel_register(sm,
id, name,
behavior, sm_eval,
sm_setinfo)secmodel
framework and stores its description inside sm.
secmodel description.secmodel.secmodel.secmodel_<model>_eval()
callback used by a secmodel to register an
evaluation routine that can be queried later by another security
model.secmodel_<model>_setinfo()
callback used by a secmodel to register a
routine that permits other security models to alter the
secmodel internals. Currently not
implemented.secmodel_deregister(sm)secmodel described by
sm.secmodel_eval(id,
what, arg,
ret)secmodel framework.secmodel.secmodel.secmodel.If successful, functions return 0. Otherwise, the following error values are returned:
EEXIST]secmodel is already registered.EFAULT]EINVAL]ENOENT]secmodel does not exist, or it does
not implement an evaluation callback.Before writing a security model one should be familiar with the kauth(9) KPI, its limitations, requirements, and so on. See kauth(9) for details.
A security model is based on the kernel 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:
MODULE()
declaration and a
secmodel_<model>_modcmd()
function used to start (through MODULE_CMD_INIT)
and stop (through MODULE_CMD_FINI) the
secmodel.secmodel_<model>_init()
and
secmodel_<model>_start(),
used to initialize and start the security model, and another function
called
secmodel_<model>_stop(),
to stop the security model in case the module is to be unloaded.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.
KAUTH_SCOPE_CRED, is
required.secmodel_register(),
and deregister itself before being stopped using
secmodel_deregister().Below is sample code for a kauth(9) network scope listener for the jenna security model. It is used to allow users with a user-id below 1000 to bind to reserved ports (for example, 22/TCP):
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) < 1000)
result = KAUTH_RESULT_ALLOW;
}
break;
}
return (result);
}
There are two main issues, however, with that listener, that you should be aware of when approaching to write your own security model:
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.
There are several things you should remember when writing a security model:
secmodel
implementation of the desired policy. Certain rights can grant more
privileges on the system than others, like allowing calls to
chroot(2) or mounting a
file-system.One of the shortcomings of 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.
To properly "stack" minor adjustments on-top of an existing security model, one could use one of two approaches:
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.
Here is example code that implements the above:
#include <secmodel/bsd44/bsd44.h>
/*
* 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) < 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);
}
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) < 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);
}
The following is a list of security models available in the default NetBSD distribution.
The core of the secmodel implementation is
in sys/secmodel/secmodel.c.
The header file
<secmodel/secmodel.h>
describes the public interface.
To make it easier on developers to write new security models from
scratch, NetBSD maintains an example
secmodel under
share/examples/secmodel/.
kauth(9), module(9), secmodel_bsd44(9), secmodel_extensions(9), secmodel_overlay(9), secmodel_securelevel(9), secmodel_suser(9)
Kernel Authorization was introduced in NetBSD 4.0 as the subsystem responsible for authorization and credential management. Before its introduction, there were several ways for providing resource access control:
suser().The problem with the above is that the interface ("can X do Y?") was tightly coupled with the implementation ("is X Z?"). kauth(9) allows separating them, dispatching requests with highly detailed context using a consistent and clear KPI.
The secmodel framework was extended in
NetBSD 6.0 to implement
secmodel registration and evaluation procedure
calls.
Elad Efrat <elad@NetBSD.org>
| December 4, 2011 | NetBSD 11.0 |