| 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.3 |