Add a new scope, the credentials scope, which is internal to the kauth(9)

implementation and meant to be used by security models to hook credential
related operations (init, fork, copy, free -- hooked in kauth_cred_alloc(),
kauth_proc_fork(), kauth_cred_clone(), and kauth_cred_free(), respectively)
and document it.

Add specificdata to credentials, and routines to register/deregister new
"keys", as well as set/get routines. This allows security models to add
their own private data to a kauth_cred_t.

The above two, combined, allow security models to control inheritance of
their own private data in credentials which is a requirement for doing
stuff like, I dunno, capabilities?
This commit is contained in:
elad 2007-01-31 10:08:23 +00:00
parent b7e0d69761
commit c439bcfe43
3 changed files with 258 additions and 20 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: kauth.9,v 1.50 2007/01/28 00:21:04 elad Exp $
.\" $NetBSD: kauth.9,v 1.51 2007/01/31 10:08:23 elad Exp $
.\"
.\" Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
.\" All rights reserved.
@ -25,7 +25,7 @@
.\" (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 January 28, 2007
.Dd January 31, 2007
.Dt KAUTH 9
.Os
.Sh NAME
@ -724,6 +724,67 @@ passed as
.Ar arg2
to the listener, is device-specific data that may be associated with the
request.
.Ss Credentials Scope
The credentials scope,
.Dq org.netbsd.kauth.cred ,
is a special scope used internally by the
.Nm
framework to provide hooking to credential-related operations.
.Pp
It is a
.Dq notify-only
scope, allowing hooking operations such as initialization of new credentials,
credential inheritance during a fork, and copying and freeing of credentials.
The main purpose for this scope is to give a security model a way to control
the aforementioned operations, especially in cases where the credentials
hold security model-private data.
.Pp
Notifications are made using the following function, which is internal to
.Nm :
.Pp
.Ft int Fn kauth_cred_hook "kauth_cred_t cred" "kauth_action_t action" \
"void *arg0" "void *arg1"
.Pp
With the following actions:
.Bl -tag
.It Dv KAUTH_CRED_COPY
The credentials are being copied.
.Ar cred
are the credentials of the lwp context doing the copy, and
.Ar arg0
and
.Ar arg1
are both
.Ft kauth_cred_t
representing the
.Dq from
and
.Dq to
credentials, respectively.
.It Dv KAUTH_CRED_FORK
The credentials are being inherited from a parent to a child process during a
fork.
.Pp
.Ar cred
are the credentials of the lwp context doing the copy, and
.Ar arg0
and
.Ar arg1
are both
.Ft struct proc *
of the parent and child processes, respectively.
.It Dv KAUTH_CRED_FREE
The credentials in
.Ar cred
are being freed.
.It Dv KAUTH_CRED_INIT
The credentials in
.Ar cred
are being initialized.
.El
.Pp
Since this is a notify-only scope, all listeners are required to return
.Dv KAUTH_RESULT_ALLOW .
.Ss Credentials Accessors and Mutators
.Nm
has a variety of accessor and mutator routines to handle
@ -841,23 +902,75 @@ The number of groups in
.Ar cred
will be returned.
.El
.Ss Credentials Inheritance and Reference Counting
.Ss Credential Private Data
.Nm
provides a KPI for handling a
.Ft kauth_cred_t
in shared credentials situations and credential inheritance.
provides an interface to allow attaching security-model private data to
credentials.
.Pp
The use of this interface has two parts that can be divided to direct and
indirect control of the private-data.
Directly controlling the private data is done by using the below routines,
while the indirect control is often dictated by events such as process
fork, and is handled by listening on the credentials scope (see above).
.Pp
Attaching private data to credentials works by registering a key to serve
as a unique identifier, distinguishing various sets of private data that
may be associated with the credentials.
Registering, and deregistering, a key is done by using these routines:
.Pp
.Bl -tag
.It Ft int Fn kauth_register_key "const char *name" "kauth_key_t *keyp"
Register new key for private data for
.Ar name
(usually, the security model name).
.Ar keyp
will be used to return the key to be used in further calls.
.Pp
The function returns 0 on success and an error code (see
.Xr errno 2 )
on failure.
.It Ft int Fn kauth_deregister_key "kauth_key_t key"
Deregister private data key
.Ar key .
.El
.Pp
Once registered, private data may be manipulated by the following routines:
.Bl -tag
.It Ft void Fn kauth_cred_setdata "kauth_cred_t cred" "kauth_key_t key" \
"void *data"
Set private data for
.Ar key
in
.Ar cred
to be
.Ar data .
.It Ft void * Fn kauth_cred_getdata "kauth_cred_t cred" "kauth_key_t key"
Retrieve private data for
.Ar key
in
.Ar cred .
.El
.Pp
Note that it is required to use the above routines every time the private
data is changed, i.e., using
.Fn kauth_cred_getdata
and later modifying the private data should be accompanied by a call to
.Fn kauth_cred_setdata
with the
.Dq new
private data.
.Ss Credential Inheritance and Reference Counting
.Nm
provides an interface for handling shared credentials.
.Pp
When a
.Ft kauth_cred_t
is first allocated, its reference count is set to 1.
However, with time, its reference count can grow as more objects (processes,
LWPs, files, etc.) reference it.
One such case is during a
.Xr fork 2
where the child process and its LWPs inherit the credentials of the parent.
.Pp
The following routines are available for managing credentials reference
counting and inheritance:
counting:
.Bl -tag
.It Ft void Fn kauth_cred_hold "kauth_cred_t cred"
Increases reference count to
@ -870,12 +983,20 @@ by one.
.Pp
If the reference count dropped to zero, the memory used by
.Ar cred
will be returned back to the memory pool.
.It Ft void kauth_proc_fork "struct proc *parent" "struct proc *child"
Called during a
.Xr fork 2
to perform credential inheritance.
will be freed.
.El
.Pp
Credential inheritance happens during a
.Xr fork 2 ,
and is handled by the following function:
.Pp
.Ft void Fn kauth_proc_fork "struct proc *parent" "struct proc *child"
.Pp
When called, it references the parent's credentials from the child,
and calls the credentials scope's hook with the
.Dv KAUTH_CRED_FORK
action to allow security model-specific handling of the inheritance
to take place.
.Ss Credentials Memory Management
Data-structures for credentials, listeners, and scopes are allocated from
memory pools managed by the

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_auth.c,v 1.40 2007/01/26 23:50:36 elad Exp $ */
/* $NetBSD: kern_auth.c,v 1.41 2007/01/31 10:08:23 elad Exp $ */
/*-
* Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_auth.c,v 1.40 2007/01/26 23:50:36 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_auth.c,v 1.41 2007/01/31 10:08:23 elad Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -38,6 +38,15 @@ __KERNEL_RCSID(0, "$NetBSD: kern_auth.c,v 1.40 2007/01/26 23:50:36 elad Exp $");
#include <sys/pool.h>
#include <sys/kauth.h>
#include <sys/kmem.h>
#include <sys/specificdata.h>
/*
* Secmodel-specific credentials.
*/
struct kauth_key {
const char *ks_secmodel; /* secmodel */
specificdata_key_t ks_key; /* key */
};
/*
* Credentials.
@ -53,6 +62,7 @@ struct kauth_cred {
gid_t cr_svgid; /* saved effective group id */
u_int cr_ngroups; /* number of groups */
gid_t cr_groups[NGROUPS]; /* group memberships */
specificdata_reference cr_sd; /* specific data */
};
/*
@ -76,6 +86,8 @@ struct kauth_scope {
SIMPLEQ_ENTRY(kauth_scope) next_scope; /* scope list */
};
static int kauth_cred_hook(kauth_cred_t, kauth_action_t, void *, void *);
static POOL_INIT(kauth_cred_pool, sizeof(struct kauth_cred), 0, 0, 0,
"kauthcredpl", &pool_allocator_nointr);
@ -90,9 +102,12 @@ static kauth_scope_t kauth_builtin_scope_process;
static kauth_scope_t kauth_builtin_scope_network;
static kauth_scope_t kauth_builtin_scope_machdep;
static kauth_scope_t kauth_builtin_scope_device;
static kauth_scope_t kauth_builtin_scope_cred;
static unsigned int nsecmodels = 0;
static specificdata_domain_t kauth_domain;
/* Allocate new, empty kauth credentials. */
kauth_cred_t
kauth_cred_alloc(void)
@ -103,6 +118,8 @@ kauth_cred_alloc(void)
memset(cred, 0, sizeof(*cred));
simple_lock_init(&cred->cr_lock);
cred->cr_refcnt = 1;
specificdata_init(kauth_domain, &cred->cr_sd);
kauth_cred_hook(cred, KAUTH_CRED_INIT, NULL, NULL);
return (cred);
}
@ -132,8 +149,11 @@ kauth_cred_free(kauth_cred_t cred)
refcnt = --cred->cr_refcnt;
simple_unlock(&cred->cr_lock);
if (refcnt == 0)
if (refcnt == 0) {
kauth_cred_hook(cred, KAUTH_CRED_FREE, NULL, NULL);
specificdata_fini(kauth_domain, &cred->cr_sd);
pool_put(&kauth_cred_pool, cred);
}
}
void
@ -151,6 +171,8 @@ kauth_cred_clone(kauth_cred_t from, kauth_cred_t to)
to->cr_svgid = from->cr_svgid;
to->cr_ngroups = from->cr_ngroups;
memcpy(to->cr_groups, from->cr_groups, sizeof(to->cr_groups));
kauth_cred_hook(from, KAUTH_CRED_COPY, to, NULL);
}
/*
@ -203,6 +225,9 @@ kauth_proc_fork(struct proc *parent, struct proc *child)
kauth_cred_hold(parent->p_cred);
child->p_cred = parent->p_cred;
/* mutex_exit(&parent->p_mutex); */
kauth_cred_hook(parent->p_cred, KAUTH_CRED_FORK, parent,
child);
}
uid_t
@ -377,6 +402,58 @@ kauth_cred_getgroups(kauth_cred_t cred, gid_t *grbuf, size_t len)
return (0);
}
int
kauth_register_key(const char *secmodel, kauth_key_t *result)
{
kauth_key_t k;
specificdata_key_t key;
int error;
KASSERT(result != NULL);
error = specificdata_key_create(kauth_domain, &key, NULL);
if (error)
return (error);
k = kmem_alloc(sizeof(*k), KM_SLEEP);
k->ks_secmodel = secmodel;
k->ks_key = key;
*result = k;
return (0);
}
int
kauth_deregister_key(kauth_key_t key)
{
KASSERT(key != NULL);
specificdata_key_delete(kauth_domain, key->ks_key);
kmem_free(key, sizeof(*key));
return (0);
}
void *
kauth_cred_getdata(kauth_cred_t cred, kauth_key_t key)
{
KASSERT(cred != NULL);
KASSERT(key != NULL);
return (specificdata_getspecific(kauth_domain, &cred->cr_sd,
key->ks_key));
}
void
kauth_cred_setdata(kauth_cred_t cred, kauth_key_t key, void *data)
{
KASSERT(cred != NULL);
KASSERT(key != NULL);
specificdata_setspecific(kauth_domain, &cred->cr_sd, key->ks_key, data);
}
/*
* Match uids in two credentials.
*/
@ -613,7 +690,9 @@ kauth_register_scope(const char *id, kauth_scope_callback_t callback,
* Initialize the kernel authorization subsystem.
*
* Initialize the scopes list lock.
* Register built-in scopes: generic, process.
* Create specificdata domain.
* Register the credentials scope, used in kauth(9) internally.
* Register built-in scopes: generic, system, process, network, machdep, device.
*/
void
kauth_init(void)
@ -621,6 +700,13 @@ kauth_init(void)
SIMPLEQ_INIT(&scope_list);
simple_lock_init(&scopes_lock);
/* Create specificdata domain. */
kauth_domain = specificdata_domain_create();
/* Register credentials scope. */
kauth_builtin_scope_cred =
kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL);
/* Register generic scope. */
kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC,
NULL, NULL);
@ -862,6 +948,20 @@ kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits,
data, NULL));
}
static int
kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0,
void *arg1)
{
int r;
r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action,
arg0, arg1, NULL, NULL);
KASSERT(r == 0);
return (r);
}
void
secmodel_register(void)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: kauth.h,v 1.35 2007/01/20 16:47:38 elad Exp $ */
/* $NetBSD: kauth.h,v 1.36 2007/01/31 10:08:23 elad Exp $ */
/*-
* Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
@ -48,6 +48,7 @@ typedef struct kauth_listener *kauth_listener_t;
typedef uint32_t kauth_action_t;
typedef int (*kauth_scope_callback_t)(kauth_cred_t, kauth_action_t,
void *, void *, void *, void *, void *);
typedef struct kauth_key *kauth_key_t;
/*
* Possible return values for a listener.
@ -65,6 +66,7 @@ typedef int (*kauth_scope_callback_t)(kauth_cred_t, kauth_action_t,
#define KAUTH_SCOPE_NETWORK "org.netbsd.kauth.network"
#define KAUTH_SCOPE_MACHDEP "org.netbsd.kauth.machdep"
#define KAUTH_SCOPE_DEVICE "org.netbsd.kauth.device"
#define KAUTH_SCOPE_CRED "org.netbsd.kauth.cred"
/*
* Generic scope - actions.
@ -217,6 +219,16 @@ enum kauth_device_req {
KAUTH_REQ_DEVICE_RAWIO_SPEC_RW,
};
/*
* Credentials scope - actions.
*/
enum {
KAUTH_CRED_INIT=1,
KAUTH_CRED_FORK,
KAUTH_CRED_COPY,
KAUTH_CRED_FREE
};
/*
* Device scope, passthru request - identifiers.
*/
@ -290,6 +302,11 @@ u_int kauth_cred_getrefcnt(kauth_cred_t);
int kauth_cred_setgroups(kauth_cred_t, gid_t *, size_t, uid_t);
int kauth_cred_getgroups(kauth_cred_t, gid_t *, size_t);
int kauth_register_key(const char *, kauth_key_t *);
int kauth_deregister_key(kauth_key_t);
void kauth_cred_setdata(kauth_cred_t, kauth_key_t, void *);
void *kauth_cred_getdata(kauth_cred_t, kauth_key_t);
int kauth_cred_uidmatch(kauth_cred_t, kauth_cred_t);
void kauth_uucred_to_cred(kauth_cred_t, const struct uucred *);
void kauth_cred_to_uucred(struct uucred *, const kauth_cred_t);