Move per-process audit state from a pointer in the proc structure to

embedded storage in struct ucred.  This allows audit state to be cached
with the thread, avoiding locking operations with each system call, and
makes it available in asynchronous execution contexts, such as deep in
the network stack or VFS.

Reviewed by:	csjp
Approved by:	re (kensmith)
Obtained from:	TrustedBSD Project
This commit is contained in:
Robert Watson 2007-06-07 22:27:15 +00:00
parent d3cdd95ce0
commit faef53711b
10 changed files with 179 additions and 211 deletions

View File

@ -441,8 +441,7 @@ proc0_init(void *dummy __unused)
p->p_ucred->cr_ruidinfo = uifind(0);
p->p_ucred->cr_prison = NULL; /* Don't jail it. */
#ifdef AUDIT
audit_proc_alloc(p);
audit_proc_kproc0(p);
audit_cred_kproc0(p->p_ucred);
#endif
#ifdef MAC
mac_create_proc0(p->p_ucred);
@ -707,7 +706,7 @@ create_init(const void *udata __unused)
mac_create_proc1(newcred);
#endif
#ifdef AUDIT
audit_proc_init(initproc);
audit_cred_proc1(newcred);
#endif
initproc->p_ucred = newcred;
PROC_UNLOCK(initproc);

View File

@ -810,9 +810,6 @@ kern_wait(struct thread *td, pid_t pid, int *status, int options,
vm_waitproc(p);
#ifdef MAC
mac_destroy_proc(p);
#endif
#ifdef AUDIT
audit_proc_free(p);
#endif
KASSERT(FIRST_THREAD_IN_PROC(p),
("kern_wait: no residual thread!"));

View File

@ -278,9 +278,6 @@ fork1(td, flags, pages, procp)
newproc = uma_zalloc(proc_zone, M_WAITOK);
#ifdef MAC
mac_init_proc(newproc);
#endif
#ifdef AUDIT
audit_proc_alloc(newproc);
#endif
knlist_init(&newproc->p_klist, &newproc->p_mtx, NULL, NULL, NULL);
STAILQ_INIT(&newproc->p_ktr);
@ -510,9 +507,6 @@ fork1(td, flags, pages, procp)
p2->p_sflag = PS_INMEM;
PROC_SUNLOCK(p2);
td2->td_ucred = crhold(p2->p_ucred);
#ifdef AUDIT
audit_proc_fork(p1, p2);
#endif
pargs_hold(p2->p_args);
if (flags & RFSIGSHARE) {
@ -752,9 +746,6 @@ fork1(td, flags, pages, procp)
sx_xunlock(&allproc_lock);
#ifdef MAC
mac_destroy_proc(newproc);
#endif
#ifdef AUDIT
audit_proc_free(newproc);
#endif
uma_zfree(proc_zone, newproc);
if (p1->p_flag & P_HADTHREADS) {

View File

@ -1763,6 +1763,9 @@ crget(void)
MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
refcount_init(&cr->cr_ref, 1);
#ifdef AUDIT
audit_cred_init(cr);
#endif
#ifdef MAC
mac_init_cred(cr);
#endif
@ -1804,6 +1807,9 @@ crfree(struct ucred *cr)
*/
if (jailed(cr))
prison_free(cr->cr_prison);
#ifdef AUDIT
audit_cred_destroy(cr);
#endif
#ifdef MAC
mac_destroy_cred(cr);
#endif
@ -1836,6 +1842,9 @@ crcopy(struct ucred *dest, struct ucred *src)
uihold(dest->cr_ruidinfo);
if (jailed(dest))
prison_hold(dest->cr_prison);
#ifdef AUDIT
audit_cred_copy(src, dest);
#endif
#ifdef MAC
mac_copy_cred(src, dest);
#endif

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 1999-2005 Apple Computer, Inc.
* Copyright (c) 2006 Robert N. M. Watson
* Copyright (c) 2006-2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -71,7 +71,7 @@
#include <vm/uma.h>
static uma_zone_t audit_record_zone;
static MALLOC_DEFINE(M_AUDITPROC, "audit_proc", "Audit process storage");
static MALLOC_DEFINE(M_AUDITCRED, "audit_cred", "Audit cred storage");
MALLOC_DEFINE(M_AUDITDATA, "audit_data", "Audit data storage");
MALLOC_DEFINE(M_AUDITPATH, "audit_path", "Audit path storage");
MALLOC_DEFINE(M_AUDITTEXT, "audit_text", "Audit text storage");
@ -176,13 +176,11 @@ audit_record_ctor(void *mem, int size, void *arg, int flags)
ar->k_ar.ar_subj_ruid = td->td_ucred->cr_ruid;
ar->k_ar.ar_subj_rgid = td->td_ucred->cr_rgid;
ar->k_ar.ar_subj_egid = td->td_ucred->cr_groups[0];
PROC_LOCK(td->td_proc);
ar->k_ar.ar_subj_auid = td->td_proc->p_au->ai_auid;
ar->k_ar.ar_subj_asid = td->td_proc->p_au->ai_asid;
ar->k_ar.ar_subj_auid = td->td_ucred->cr_audit.ai_auid;
ar->k_ar.ar_subj_asid = td->td_ucred->cr_audit.ai_asid;
ar->k_ar.ar_subj_pid = td->td_proc->p_pid;
ar->k_ar.ar_subj_amask = td->td_proc->p_au->ai_mask;
ar->k_ar.ar_subj_term_addr = td->td_proc->p_au->ai_termid;
PROC_UNLOCK(td->td_proc);
ar->k_ar.ar_subj_amask = td->td_ucred->cr_audit.ai_mask;
ar->k_ar.ar_subj_term_addr = td->td_ucred->cr_audit.ai_termid;
return (0);
}
@ -470,11 +468,11 @@ audit_syscall_enter(unsigned short code, struct thread *td)
* Check which audit mask to use; either the kernel non-attributable
* event mask or the process audit mask.
*/
auid = td->td_proc->p_au->ai_auid;
auid = td->td_ucred->cr_audit.ai_auid;
if (auid == AU_DEFAUDITID)
aumask = &audit_nae_mask;
else
aumask = &td->td_proc->p_au->ai_mask;
aumask = &td->td_ucred->cr_audit.ai_mask;
/*
* Allocate an audit record, if preselection allows it, and store in
@ -533,15 +531,50 @@ audit_syscall_exit(int error, struct thread *td)
}
/*
* Allocate storage for a new process (init, or otherwise).
* Copy audit state from an existing credential to a new credential.
*/
void
audit_proc_alloc(struct proc *p)
audit_cred_copy(struct ucred *src, struct ucred *dest)
{
KASSERT(p->p_au == NULL, ("audit_proc_alloc: p->p_au != NULL (%d)",
p->p_pid));
p->p_au = malloc(sizeof(*(p->p_au)), M_AUDITPROC, M_WAITOK);
bcopy(&src->cr_audit, &dest->cr_audit, sizeof(dest->cr_audit));
}
/*
* Free audit state from a credential when the credential is freed.
*/
void
audit_cred_destroy(struct ucred *cred)
{
bzero(&cred->cr_audit, sizeof(cred->cr_audit));
}
/*
* Allocate audit state for a new credential.
*/
void
audit_cred_init(struct ucred *cred)
{
bzero(&cred->cr_audit, sizeof(cred->cr_audit));
}
/*
* Initialize audit information for the first kernel process (proc 0) and for
* the first user process (init).
*/
void
audit_cred_kproc0(struct ucred *cred)
{
}
void
audit_cred_proc1(struct ucred *cred)
{
cred->cr_audit.ai_auid = AU_DEFAUDITID;
}
/*
@ -563,62 +596,3 @@ audit_thread_free(struct thread *td)
KASSERT(td->td_ar == NULL, ("audit_thread_free: td_ar != NULL"));
}
/*
* Initialize audit information for the first kernel process (proc 0) and for
* the first user process (init).
*
* XXX It is not clear what the initial values should be for audit ID,
* session ID, etc.
*/
void
audit_proc_kproc0(struct proc *p)
{
KASSERT(p->p_au != NULL, ("audit_proc_kproc0: p->p_au == NULL (%d)",
p->p_pid));
bzero(p->p_au, sizeof(*(p)->p_au));
}
void
audit_proc_init(struct proc *p)
{
KASSERT(p->p_au != NULL, ("audit_proc_init: p->p_au == NULL (%d)",
p->p_pid));
bzero(p->p_au, sizeof(*(p)->p_au));
p->p_au->ai_auid = AU_DEFAUDITID;
}
/*
* Copy the audit info from the parent process to the child process when a
* fork takes place.
*/
void
audit_proc_fork(struct proc *parent, struct proc *child)
{
PROC_LOCK_ASSERT(parent, MA_OWNED);
PROC_LOCK_ASSERT(child, MA_OWNED);
KASSERT(parent->p_au != NULL,
("audit_proc_fork: parent->p_au == NULL (%d)", parent->p_pid));
KASSERT(child->p_au != NULL,
("audit_proc_fork: child->p_au == NULL (%d)", child->p_pid));
bcopy(parent->p_au, child->p_au, sizeof(*child->p_au));
}
/*
* Free the auditing structure for the process.
*/
void
audit_proc_free(struct proc *p)
{
KASSERT(p->p_au != NULL, ("p->p_au == NULL (%d)", p->p_pid));
free(p->p_au, M_AUDITPROC);
p->p_au = NULL;
}

View File

@ -171,11 +171,11 @@ void audit_arg_file(struct proc *p, struct file *fp);
void audit_arg_argv(char *argv, int argc, int length);
void audit_arg_envv(char *envv, int envc, int length);
void audit_sysclose(struct thread *td, int fd);
void audit_proc_alloc(struct proc *p);
void audit_proc_kproc0(struct proc *p);
void audit_proc_init(struct proc *p);
void audit_proc_fork(struct proc *parent, struct proc *child);
void audit_proc_free(struct proc *p);
void audit_cred_copy(struct ucred *src, struct ucred *dest);
void audit_cred_destroy(struct ucred *cred);
void audit_cred_init(struct ucred *cred);
void audit_cred_kproc0(struct ucred *cred);
void audit_cred_proc1(struct ucred *cred);
void audit_thread_alloc(struct thread *td);
void audit_thread_free(struct thread *td);

View File

@ -364,13 +364,13 @@ audit_arg_process(struct proc *p)
if (ar == NULL)
return;
ar->k_ar.ar_arg_auid = p->p_au->ai_auid;
ar->k_ar.ar_arg_auid = p->p_ucred->cr_audit.ai_auid;
ar->k_ar.ar_arg_euid = p->p_ucred->cr_uid;
ar->k_ar.ar_arg_egid = p->p_ucred->cr_groups[0];
ar->k_ar.ar_arg_ruid = p->p_ucred->cr_ruid;
ar->k_ar.ar_arg_rgid = p->p_ucred->cr_rgid;
ar->k_ar.ar_arg_asid = p->p_au->ai_asid;
ar->k_ar.ar_arg_termid_addr = p->p_au->ai_termid;
ar->k_ar.ar_arg_asid = p->p_ucred->cr_audit.ai_asid;
ar->k_ar.ar_arg_termid_addr = p->p_ucred->cr_audit.ai_termid;
ar->k_ar.ar_arg_pid = p->p_pid;
ARG_SET_VALID(ar, ARG_AUID | ARG_EUID | ARG_EGID | ARG_RUID |
ARG_RGID | ARG_ASID | ARG_TERMID_ADDR | ARG_PID | ARG_PROCESS);

View File

@ -156,6 +156,7 @@ audit(struct thread *td, struct audit_args *uap)
int
auditon(struct thread *td, struct auditon_args *uap)
{
struct ucred *newcred, *oldcred;
int error;
union auditon_udata udata;
struct proc *tp;
@ -313,47 +314,53 @@ auditon(struct thread *td, struct auditon_args *uap)
case A_GETPINFO:
if (udata.au_aupinfo.ap_pid < 1)
return (EINVAL);
if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
return (EINVAL);
if (p_cansee(td, tp) != 0) {
PROC_UNLOCK(tp);
return (EINVAL);
}
if (tp->p_au->ai_termid.at_type == AU_IPv6) {
if (tp->p_ucred->cr_audit.ai_termid.at_type == AU_IPv6) {
PROC_UNLOCK(tp);
return (EINVAL);
}
udata.au_aupinfo.ap_auid = tp->p_au->ai_auid;
udata.au_aupinfo.ap_auid =
tp->p_ucred->cr_audit.ai_auid;
udata.au_aupinfo.ap_mask.am_success =
tp->p_au->ai_mask.am_success;
tp->p_ucred->cr_audit.ai_mask.am_success;
udata.au_aupinfo.ap_mask.am_failure =
tp->p_au->ai_mask.am_failure;
tp->p_ucred->cr_audit.ai_mask.am_failure;
udata.au_aupinfo.ap_termid.machine =
tp->p_au->ai_termid.at_addr[0];
tp->p_ucred->cr_audit.ai_termid.at_addr[0];
udata.au_aupinfo.ap_termid.port =
(dev_t)tp->p_au->ai_termid.at_port;
udata.au_aupinfo.ap_asid = tp->p_au->ai_asid;
(dev_t)tp->p_ucred->cr_audit.ai_termid.at_port;
udata.au_aupinfo.ap_asid =
tp->p_ucred->cr_audit.ai_asid;
PROC_UNLOCK(tp);
break;
case A_SETPMASK:
if (udata.au_aupinfo.ap_pid < 1)
return (EINVAL);
if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
return (EINVAL);
if (p_cansee(td, tp) != 0) {
PROC_UNLOCK(tp);
newcred = crget();
if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) {
crfree(newcred);
return (EINVAL);
}
tp->p_au->ai_mask.am_success =
if (p_cansee(td, tp) != 0) {
PROC_UNLOCK(tp);
crfree(newcred);
return (EINVAL);
}
oldcred = tp->p_ucred;
crcopy(newcred, oldcred);
newcred->cr_audit.ai_mask.am_success =
udata.au_aupinfo.ap_mask.am_success;
tp->p_au->ai_mask.am_failure =
newcred->cr_audit.ai_mask.am_failure =
udata.au_aupinfo.ap_mask.am_failure;
td->td_proc->p_ucred = newcred;
PROC_UNLOCK(tp);
crfree(oldcred);
break;
case A_SETFSIZE:
@ -373,13 +380,16 @@ auditon(struct thread *td, struct auditon_args *uap)
return (EINVAL);
if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL)
return (EINVAL);
udata.au_aupinfo_addr.ap_auid = tp->p_au->ai_auid;
udata.au_aupinfo_addr.ap_auid =
tp->p_ucred->cr_audit.ai_auid;
udata.au_aupinfo_addr.ap_mask.am_success =
tp->p_au->ai_mask.am_success;
tp->p_ucred->cr_audit.ai_mask.am_success;
udata.au_aupinfo_addr.ap_mask.am_failure =
tp->p_au->ai_mask.am_failure;
udata.au_aupinfo_addr.ap_termid = tp->p_au->ai_termid;
udata.au_aupinfo_addr.ap_asid = tp->p_au->ai_asid;
tp->p_ucred->cr_audit.ai_mask.am_failure;
udata.au_aupinfo_addr.ap_termid =
tp->p_ucred->cr_audit.ai_termid;
udata.au_aupinfo_addr.ap_asid =
tp->p_ucred->cr_audit.ai_asid;
PROC_UNLOCK(tp);
break;
@ -431,64 +441,51 @@ int
getauid(struct thread *td, struct getauid_args *uap)
{
int error;
au_id_t id;
if (jailed(td->td_ucred))
return (ENOSYS);
error = priv_check(td, PRIV_AUDIT_GETAUDIT);
if (error)
return (error);
/*
* XXX: Integer read on static pointer dereference: doesn't need
* locking?
*/
PROC_LOCK(td->td_proc);
id = td->td_proc->p_au->ai_auid;
PROC_UNLOCK(td->td_proc);
return copyout(&id, uap->auid, sizeof(id));
return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid,
sizeof(td->td_ucred->cr_audit.ai_auid)));
}
/* ARGSUSED */
int
setauid(struct thread *td, struct setauid_args *uap)
{
int error;
struct ucred *newcred, *oldcred;
au_id_t id;
int error;
if (jailed(td->td_ucred))
return (ENOSYS);
error = priv_check(td, PRIV_AUDIT_SETAUDIT);
if (error)
return (error);
error = copyin(uap->auid, &id, sizeof(id));
if (error)
return (error);
audit_arg_auid(id);
#ifdef MAC
error = mac_check_proc_setauid(td->td_ucred, id);
if (error)
return (error);
#endif
/*
* XXX: Integer write on static pointer dereference: doesn't need
* locking?
*
* XXXAUDIT: Might need locking to serialize audit events in the same
* order as change events? Or maybe that's an under-solveable
* problem.
*
* XXXRW: Test privilege while holding the proc lock?
*/
newcred = crget();
PROC_LOCK(td->td_proc);
td->td_proc->p_au->ai_auid = id;
oldcred = td->td_proc->p_ucred;
crcopy(newcred, oldcred);
#ifdef MAC
error = mac_check_proc_setauid(oldcred, id);
if (error)
goto fail;
#endif
error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
if (error)
goto fail;
newcred->cr_audit.ai_auid = id;
td->td_proc->p_ucred = newcred;
PROC_UNLOCK(td->td_proc);
crfree(oldcred);
return (0);
fail:
PROC_UNLOCK(td->td_proc);
crfree(newcred);
return (error);
}
/*
@ -506,108 +503,108 @@ getaudit(struct thread *td, struct getaudit_args *uap)
error = priv_check(td, PRIV_AUDIT_GETAUDIT);
if (error)
return (error);
PROC_LOCK(td->td_proc);
if (td->td_proc->p_au->ai_termid.at_type == AU_IPv6) {
PROC_UNLOCK(td->td_proc);
return (E2BIG);
}
bzero(&ai, sizeof(ai));
ai.ai_auid = td->td_proc->p_au->ai_auid;
ai.ai_mask = td->td_proc->p_au->ai_mask;
ai.ai_asid = td->td_proc->p_au->ai_asid;
ai.ai_termid.machine = td->td_proc->p_au->ai_termid.at_addr[0];
ai.ai_termid.port = td->td_proc->p_au->ai_termid.at_port;
PROC_UNLOCK(td->td_proc);
return (copyout(&ai, uap->auditinfo, sizeof(ai)));
ai.ai_auid = td->td_ucred->cr_audit.ai_auid;
ai.ai_mask = td->td_ucred->cr_audit.ai_mask;
ai.ai_asid = td->td_ucred->cr_audit.ai_asid;
ai.ai_termid.machine = td->td_ucred->cr_audit.ai_termid.at_addr[0];
ai.ai_termid.port = td->td_ucred->cr_audit.ai_termid.at_port;
return (copyout(&ai, uap->auditinfo, sizeof(&ai)));
}
/* ARGSUSED */
int
setaudit(struct thread *td, struct setaudit_args *uap)
{
struct ucred *newcred, *oldcred;
struct auditinfo ai;
int error;
if (jailed(td->td_ucred))
return (ENOSYS);
error = priv_check(td, PRIV_AUDIT_SETAUDIT);
if (error)
return (error);
error = copyin(uap->auditinfo, &ai, sizeof(ai));
if (error)
return (error);
audit_arg_auditinfo(&ai);
#ifdef MAC
error = mac_check_proc_setaudit(td->td_ucred, &ai);
if (error)
return (error);
#endif
/*
* XXXRW: Test privilege while holding the proc lock?
*/
newcred = crget();
PROC_LOCK(td->td_proc);
bzero(td->td_proc->p_au, sizeof(struct auditinfo_addr));
td->td_proc->p_au->ai_auid = ai.ai_auid;
td->td_proc->p_au->ai_mask = ai.ai_mask;
td->td_proc->p_au->ai_asid = ai.ai_asid;
td->td_proc->p_au->ai_termid.at_addr[0] = ai.ai_termid.machine;
td->td_proc->p_au->ai_termid.at_port = ai.ai_termid.port;
td->td_proc->p_au->ai_termid.at_type = AU_IPv4;
oldcred = td->td_proc->p_ucred;
crcopy(newcred, oldcred);
#ifdef MAC
error = mac_check_proc_setaudit(oldcred, &ai);
if (error)
goto fail;
#endif
error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
if (error)
goto fail;
bzero(&newcred->cr_audit, sizeof(newcred->cr_audit));
newcred->cr_audit.ai_auid = ai.ai_auid;
newcred->cr_audit.ai_mask = ai.ai_mask;
newcred->cr_audit.ai_asid = ai.ai_asid;
newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine;
newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port;
newcred->cr_audit.ai_termid.at_type = AU_IPv4;
td->td_proc->p_ucred = newcred;
PROC_UNLOCK(td->td_proc);
crfree(oldcred);
return (0);
fail:
PROC_UNLOCK(td->td_proc);
crfree(newcred);
return (error);
}
/* ARGSUSED */
int
getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
{
struct auditinfo_addr aia;
int error;
if (jailed(td->td_ucred))
return (ENOSYS);
if (uap->length < sizeof(*uap->auditinfo_addr))
return (EOVERFLOW);
error = priv_check(td, PRIV_AUDIT_GETAUDIT);
if (error)
return (error);
if (uap->length < sizeof(aia))
return (EOVERFLOW);
PROC_LOCK(td->td_proc);
aia = *td->td_proc->p_au;
PROC_UNLOCK(td->td_proc);
return (copyout(&aia, uap->auditinfo_addr, sizeof(aia)));
return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr,
sizeof(*uap->auditinfo_addr)));
}
/* ARGSUSED */
int
setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
{
struct ucred *newcred, *oldcred;
struct auditinfo_addr aia;
int error;
if (jailed(td->td_ucred))
return (ENOSYS);
error = priv_check(td, PRIV_AUDIT_SETAUDIT);
if (error)
return (error);
#ifdef MAC
error = mac_check_proc_setaudit(td->td_ucred, NULL);
if (error)
return (error);
#endif
error = copyin(uap->auditinfo_addr, &aia, sizeof(aia));
if (error)
return (error);
PROC_LOCK(td->td_proc);
*td->td_proc->p_au = aia;
/* XXXRW: Audit argument. */
newcred = crget();
PROC_LOCK(td->td_proc);
oldcred = td->td_proc->p_ucred;
crcopy(newcred, oldcred);
#ifdef MAC
error = mac_check_proc_setaudit(oldcred, NULL);
if (error)
goto fail;
#endif
error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
if (error)
goto fail;
newcred->cr_audit = aia;
td->td_proc->p_ucred = newcred;
PROC_UNLOCK(td->td_proc);
crfree(oldcred);
return (0);
fail:
crfree(newcred);
return (error);
}

View File

@ -152,7 +152,6 @@ struct pargs {
* either lock is sufficient for read access, but both locks must be held
* for write access.
*/
struct auditinfo;
struct kaudit_record;
struct td_sched;
struct nlminfo;
@ -580,7 +579,6 @@ struct proc {
struct p_sched *p_sched; /* (*) Scheduler-specific data. */
STAILQ_HEAD(, ktr_request) p_ktr; /* (o) KTR event queue. */
LIST_HEAD(, mqueue_notifier) p_mqnotifier; /* (c) mqueue notifiers.*/
struct auditinfo_addr *p_au; /* (c) Process audit properties. */
};
#define p_session p_pgrp->pg_session

View File

@ -33,6 +33,8 @@
#ifndef _SYS_UCRED_H_
#define _SYS_UCRED_H_
#include <bsm/audit.h>
/*
* Credentials.
*
@ -55,6 +57,7 @@ struct ucred {
struct prison *cr_prison; /* jail(2) */
#define cr_endcopy cr_label
struct label *cr_label; /* MAC label */
struct auditinfo_addr cr_audit; /* Audit properties. */
};
#define NOCRED ((struct ucred *)0) /* no credential available */
#define FSCRED ((struct ucred *)-1) /* filesystem credential */