SECMODEL(9) | Kernel Developer's Manual | SECMODEL(9) |
secmodel
—
#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);
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.
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
.EEXIST
]secmodel
is already registered.EFAULT
]EINVAL
]ENOENT
]secmodel
does not exist, or it does
not implement an evaluation callback.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
().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.
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.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); }
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/.
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.
December 4, 2011 | NetBSD 9.0 |